xref: /haiku/src/add-ons/accelerants/radeon_hd/connector.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 uint16
121 connector_pick_atom_hpdid(uint32 connectorIndex)
122 {
123 	radeon_shared_info &info = *gInfo->shared_info;
124 
125 	uint16 atomHPDID = 0xff;
126 	uint16 hpdPinIndex = gConnector[connectorIndex]->hpdPinIndex;
127 	if (info.dceMajor >= 4
128 		&& gGPIOInfo[hpdPinIndex]->valid) {
129 
130 		// See mmDC_GPIO_HPD_A in drm for register value
131 		uint32 targetReg = AVIVO_DC_GPIO_HPD_A;
132 		if (info.dceMajor >= 13) {
133 			ERROR("WARNING: CHECK NEW DCE mmDC_GPIO_HPD_A value!\n");
134 			targetReg = POL_mmDC_GPIO_HPD_A;
135 		} else if (info.dceMajor >= 12)
136 			targetReg = POL_mmDC_GPIO_HPD_A;
137 		else if (info.dceMajor >= 11)
138 			targetReg = CAR_mmDC_GPIO_HPD_A;
139 		else if (info.dceMajor >= 10)
140 			targetReg = VOL_mmDC_GPIO_HPD_A;
141 		else if (info.dceMajor >= 8)
142 			targetReg = SEA_mmDC_GPIO_HPD_A;
143 		else if (info.dceMajor >= 6)
144 			targetReg = SI_DC_GPIO_HPD_A;
145 		else if (info.dceMajor >= 4)
146 			targetReg = EVERGREEN_DC_GPIO_HPD_A;
147 
148 		// You're drunk AMD, go home. (this makes no sense)
149 		if (gGPIOInfo[hpdPinIndex]->hwReg == targetReg) {
150 			switch(gGPIOInfo[hpdPinIndex]->hwMask) {
151 				case (1 << 0):
152 					atomHPDID = 0;
153 					break;
154 				case (1 << 8):
155 					atomHPDID = 1;
156 					break;
157 				case (1 << 16):
158 					atomHPDID = 2;
159 					break;
160 				case (1 << 24):
161 					atomHPDID = 3;
162 					break;
163 				case (1 << 26):
164 					atomHPDID = 4;
165 					break;
166 				case (1 << 28):
167 					atomHPDID = 5;
168 					break;
169 			}
170 		}
171 	}
172 	return atomHPDID;
173 }
174 
175 
176 bool
177 connector_read_edid(uint32 connectorIndex, edid1_info* edid)
178 {
179 	// ensure things are sane
180 	uint32 i2cPinIndex = gConnector[connectorIndex]->i2cPinIndex;
181 	if (gGPIOInfo[i2cPinIndex]->valid == false
182 		|| gGPIOInfo[i2cPinIndex]->i2c.valid == false) {
183 		ERROR("%s: invalid gpio %" B_PRIu32 " for connector %" B_PRIu32 "\n",
184 			__func__, i2cPinIndex, connectorIndex);
185 		return false;
186 	}
187 
188 	i2c_bus bus;
189 
190 	ddc2_init_timing(&bus);
191 	bus.cookie = (void*)gGPIOInfo[i2cPinIndex];
192 	bus.set_signals = &gpio_set_i2c_bit;
193 	bus.get_signals = &gpio_get_i2c_bit;
194 
195 	gpio_lock_i2c(bus.cookie, true);
196 	status_t edid_result = ddc2_read_edid1(&bus, edid, NULL, NULL);
197 	gpio_lock_i2c(bus.cookie, false);
198 
199 	if (edid_result != B_OK)
200 		return false;
201 
202 	TRACE("%s: found edid monitor on connector #%" B_PRId32 "\n",
203 		__func__, connectorIndex);
204 
205 	return true;
206 }
207 
208 
209 bool
210 connector_read_mode_lvds(uint32 connectorIndex, display_mode* mode)
211 {
212 	assert(mode);
213 
214 	uint8 dceMajor;
215 	uint8 dceMinor;
216 	int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
217 	uint16 offset;
218 
219 	union atomLVDSInfo {
220 		struct _ATOM_LVDS_INFO info;
221 		struct _ATOM_LVDS_INFO_V12 info_12;
222 	};
223 
224 	// Wipe out display_mode
225 	memset(mode, 0, sizeof(display_mode));
226 
227 	if (atom_parse_data_header(gAtomContext, index, NULL,
228 		&dceMajor, &dceMinor, &offset) == B_OK) {
229 
230 		union atomLVDSInfo* lvdsInfo
231 			= (union atomLVDSInfo*)(gAtomContext->bios + offset);
232 
233 		display_timing* timing = &mode->timing;
234 
235 		// Pixel Clock
236 		timing->pixel_clock
237 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usPixClk) * 10;
238 		// Horizontal
239 		timing->h_display
240 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHActive);
241 		timing->h_total = timing->h_display + B_LENDIAN_TO_HOST_INT16(
242 			lvdsInfo->info.sLCDTiming.usHBlanking_Time);
243 		timing->h_sync_start = timing->h_display
244 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncOffset);
245 		timing->h_sync_end = timing->h_sync_start
246 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usHSyncWidth);
247 		// Vertical
248 		timing->v_display
249 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVActive);
250 		timing->v_total = timing->v_display + B_LENDIAN_TO_HOST_INT16(
251 			lvdsInfo->info.sLCDTiming.usVBlanking_Time);
252 		timing->v_sync_start = timing->v_display
253 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncOffset);
254 		timing->v_sync_end = timing->v_sync_start
255 			+ B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.sLCDTiming.usVSyncWidth);
256 
257 		#if 0
258 		// Who cares.
259 		uint32 powerDelay
260 			= B_LENDIAN_TO_HOST_INT16(lvdsInfo->info.usOffDelayInMs);
261 		#endif
262 
263 		// Store special lvds flags the encoder setup needs
264 		gConnector[connectorIndex]->lvdsFlags = lvdsInfo->info.ucLVDS_Misc;
265 
266 		// Spread Spectrum ID (in SS table)
267 		gInfo->lvdsSpreadSpectrumID = lvdsInfo->info.ucSS_Id;
268 
269 		uint16 flags = B_LENDIAN_TO_HOST_INT16(
270 			lvdsInfo->info.sLCDTiming.susModeMiscInfo.usAccess);
271 
272 		if ((flags & ATOM_VSYNC_POLARITY) == 0)
273 			timing->flags |= B_POSITIVE_VSYNC;
274 		if ((flags & ATOM_HSYNC_POLARITY) == 0)
275 			timing->flags |= B_POSITIVE_HSYNC;
276 
277 		// Extra flags
278 		if ((flags & ATOM_INTERLACE) != 0)
279 			timing->flags |= B_TIMING_INTERLACED;
280 
281 		#if 0
282 		// We don't use these timing flags at the moment
283 		if ((flags & ATOM_COMPOSITESYNC) != 0)
284 			timing->flags |= MODE_FLAG_CSYNC;
285 		if ((flags & ATOM_DOUBLE_CLOCK_MODE) != 0)
286 			timing->flags |= MODE_FLAG_DBLSCAN;
287 		#endif
288 
289 		mode->h_display_start = 0;
290 		mode->v_display_start = 0;
291 		mode->virtual_width = timing->h_display;
292 		mode->virtual_height = timing->v_display;
293 
294 		// Assume 32-bit color
295 		mode->space = B_RGB32_LITTLE;
296 
297 		TRACE("%s: %" B_PRIu32 " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16
298 			" %" B_PRIu16  " %" B_PRIu16 " %" B_PRIu16 " %" B_PRIu16
299 			" %" B_PRIu16 "\n", __func__, timing->pixel_clock,
300 			timing->h_display, timing->h_sync_start, timing->h_sync_end,
301 			timing->h_total, timing->v_display, timing->v_sync_start,
302 			timing->v_sync_end, timing->v_total);
303 
304 		return true;
305 	}
306 	return false;
307 }
308 
309 
310 static status_t
311 connector_attach_gpio_i2c(uint32 connectorIndex, uint8 hwPin)
312 {
313 	gConnector[connectorIndex]->i2cPinIndex = 0;
314 	for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
315 		if (gGPIOInfo[i]->hwPin != hwPin)
316 			continue;
317 		gConnector[connectorIndex]->i2cPinIndex = i;
318 		return B_OK;
319 	}
320 
321 	// We couldnt find the GPIO pin in the known GPIO pins.
322 	TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
323 		__func__, hwPin, connectorIndex);
324 	return B_ERROR;
325 }
326 
327 
328 static status_t
329 connector_attach_gpio_router(uint32 connectorIndex, uint8 hwPin)
330 {
331 	gConnector[connectorIndex]->router.i2cPinIndex = 0;
332 	for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
333 		if (gGPIOInfo[i]->hwPin != hwPin)
334 			continue;
335 		gConnector[connectorIndex]->router.i2cPinIndex = i;
336 		return B_OK;
337 	}
338 
339 	// We couldnt find the GPIO pin in the known GPIO pins.
340 	TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
341 		__func__, hwPin, connectorIndex);
342 	return B_ERROR;
343 }
344 
345 
346 static status_t
347 connector_attach_gpio_hpd(uint32 connectorIndex, uint8 hwPin)
348 {
349     gConnector[connectorIndex]->hpdPinIndex = 0;
350 
351     for (uint32 i = 0; i < MAX_GPIO_PINS; i++) {
352         if (gGPIOInfo[i]->hwPin != hwPin)
353             continue;
354         gConnector[connectorIndex]->hpdPinIndex = i;
355         return B_OK;
356     }
357 
358 	// We couldnt find the GPIO pin in the known GPIO pins.
359     TRACE("%s: can't find GPIO pin 0x%" B_PRIX8 " for connector %" B_PRIu32 "\n",
360         __func__, hwPin, connectorIndex);
361     return B_ERROR;
362 }
363 
364 
365 static status_t
366 gpio_general_populate()
367 {
368 	int index = GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT);
369 	uint16 tableOffset;
370 	uint16 tableSize;
371 
372 	struct _ATOM_GPIO_PIN_LUT* gpioInfo;
373 
374 	if (atom_parse_data_header(gAtomContext, index, &tableSize, NULL, NULL,
375 		&tableOffset)) {
376 		ERROR("%s: could't read GPIO_Pin_LUT table from AtomBIOS index %d!\n",
377 			__func__, index);
378 	}
379 	gpioInfo = (struct _ATOM_GPIO_PIN_LUT*)(gAtomContext->bios + tableOffset);
380 
381 	int numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER)) /
382 		sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
383 
384 	// Find the next available GPIO pin index
385 	int32 gpioIndex = -1;
386 	for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) {
387 		if (!gGPIOInfo[pin]->valid) {
388 			gpioIndex = pin;
389 			break;
390 		}
391 	}
392 	if (gpioIndex < 0) {
393 		ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__);
394 		return B_ERROR;
395 	}
396 
397 	ATOM_GPIO_PIN_ASSIGNMENT* pin = gpioInfo->asGPIO_Pin;
398 	for (int i = 0; i < numIndices; i++) {
399 		if (gGPIOInfo[gpioIndex]->valid) {
400 			ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n",
401 				__func__);
402 			return B_ERROR;
403 		}
404 		gGPIOInfo[gpioIndex]->valid = true;
405 		gGPIOInfo[gpioIndex]->i2c.valid = false;
406 		gGPIOInfo[gpioIndex]->hwPin = pin->ucGPIO_ID;
407 		gGPIOInfo[gpioIndex]->hwReg
408 			= B_LENDIAN_TO_HOST_INT16(pin->usGpioPin_AIndex) * 4;
409 		gGPIOInfo[gpioIndex]->hwMask
410 			= (1 << pin->ucGpioPinBitShift);
411 		pin = (ATOM_GPIO_PIN_ASSIGNMENT*)((uint8*)pin
412 			+ sizeof(ATOM_GPIO_PIN_ASSIGNMENT));
413 
414 		TRACE("%s: general GPIO @ %" B_PRId32 ", valid: %s, "
415 			"hwPin: 0x%" B_PRIX32 "\n", __func__, gpioIndex,
416 			gGPIOInfo[gpioIndex]->valid ? "true" : "false",
417 			gGPIOInfo[gpioIndex]->hwPin);
418 
419 		gpioIndex++;
420 	}
421 	return B_OK;
422 }
423 
424 
425 static status_t
426 gpio_i2c_populate()
427 {
428 	radeon_shared_info &info = *gInfo->shared_info;
429 
430 	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
431 	uint16 tableOffset;
432 	uint16 tableSize;
433 
434 	if (atom_parse_data_header(gAtomContext, index, &tableSize,
435 		NULL, NULL, &tableOffset) != B_OK) {
436 		ERROR("%s: could't read GPIO_I2C_Info table from AtomBIOS index %d!\n",
437 			__func__, index);
438 		return B_ERROR;
439 	}
440 
441 	struct _ATOM_GPIO_I2C_INFO* i2cInfo
442 		= (struct _ATOM_GPIO_I2C_INFO*)(gAtomContext->bios + tableOffset);
443 
444 	uint32 numIndices = (tableSize - sizeof(ATOM_COMMON_TABLE_HEADER))
445 		/ sizeof(ATOM_GPIO_I2C_ASSIGMENT);
446 
447 	if (numIndices > ATOM_MAX_SUPPORTED_DEVICE) {
448 		ERROR("%s: ERROR: AtomBIOS contains more GPIO_Info items then I"
449 			"was prepared for! (seen: %" B_PRIu32 "; max: %" B_PRIu32 ")\n",
450 			__func__, numIndices, (uint32)ATOM_MAX_SUPPORTED_DEVICE);
451 		return B_ERROR;
452 	}
453 
454 	// Find the next available GPIO pin index
455 	int32 gpioIndex = -1;
456 	for(int32 pin = 0; pin < MAX_GPIO_PINS; pin++) {
457 		if (!gGPIOInfo[pin]->valid) {
458 			gpioIndex = pin;
459 			break;
460 		}
461 	}
462 	if (gpioIndex < 0) {
463 		ERROR("%s: ERROR: Out of space for additional GPIO pins!\n", __func__);
464 		return B_ERROR;
465 	}
466 
467 	for (uint32 i = 0; i < numIndices; i++) {
468 		if (gGPIOInfo[gpioIndex]->valid) {
469 			ERROR("%s: BUG: Attempting to fill already populated gpio pin!\n",
470 				__func__);
471 			return B_ERROR;
472 		}
473 		ATOM_GPIO_I2C_ASSIGMENT* gpio = &i2cInfo->asGPIO_Info[i];
474 
475 		if (info.dceMajor >= 3) {
476 			if (i == 4 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex)
477 				== 0x1fda && gpio->sucI2cId.ucAccess == 0x94) {
478 				gpio->sucI2cId.ucAccess = 0x14;
479 				TRACE("%s: BUG: GPIO override for DCE 3 occured\n", __func__);
480 			}
481 		}
482 
483 		if (info.dceMajor >= 4) {
484 			if (i == 7 && B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex)
485 				== 0x1936 && gpio->sucI2cId.ucAccess == 0) {
486 				gpio->sucI2cId.ucAccess = 0x97;
487 				gpio->ucDataMaskShift = 8;
488 				gpio->ucDataEnShift = 8;
489 				gpio->ucDataY_Shift = 8;
490 				gpio->ucDataA_Shift = 8;
491 				TRACE("%s: BUG: GPIO override for DCE 4 occured\n", __func__);
492 			}
493 		}
494 
495 		// populate gpio information
496 		gGPIOInfo[gpioIndex]->hwPin = gpio->sucI2cId.ucAccess;
497 		gGPIOInfo[gpioIndex]->i2c.hwCapable
498 			= (gpio->sucI2cId.sbfAccess.bfHW_Capable) ? true : false;
499 
500 		// GPIO mask (Allows software to control the GPIO pad)
501 		// 0 = chip access; 1 = only software;
502 		gGPIOInfo[gpioIndex]->i2c.sclMaskReg
503 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkMaskRegisterIndex) * 4;
504 		gGPIOInfo[gpioIndex]->i2c.sdaMaskReg
505 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataMaskRegisterIndex) * 4;
506 		gGPIOInfo[gpioIndex]->i2c.sclMask = 1 << gpio->ucClkMaskShift;
507 		gGPIOInfo[gpioIndex]->i2c.sdaMask = 1 << gpio->ucDataMaskShift;
508 
509 		// GPIO output / write (A) enable
510 		// 0 = GPIO input (Y); 1 = GPIO output (A);
511 		gGPIOInfo[gpioIndex]->i2c.sclEnReg
512 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkEnRegisterIndex) * 4;
513 		gGPIOInfo[gpioIndex]->i2c.sdaEnReg
514 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataEnRegisterIndex) * 4;
515 		gGPIOInfo[gpioIndex]->i2c.sclEnMask = 1 << gpio->ucClkEnShift;
516 		gGPIOInfo[gpioIndex]->i2c.sdaEnMask = 1 << gpio->ucDataEnShift;
517 
518 		// GPIO output / write (A)
519 		gGPIOInfo[gpioIndex]->i2c.sclAReg
520 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkA_RegisterIndex) * 4;
521 		gGPIOInfo[gpioIndex]->i2c.sdaAReg
522 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataA_RegisterIndex) * 4;
523 		gGPIOInfo[gpioIndex]->i2c.sclAMask = 1 << gpio->ucClkA_Shift;
524 		gGPIOInfo[gpioIndex]->i2c.sdaAMask = 1 << gpio->ucDataA_Shift;
525 
526 		// GPIO input / read (Y)
527 		gGPIOInfo[gpioIndex]->i2c.sclYReg
528 			= B_LENDIAN_TO_HOST_INT16(gpio->usClkY_RegisterIndex) * 4;
529 		gGPIOInfo[gpioIndex]->i2c.sdaYReg
530 			= B_LENDIAN_TO_HOST_INT16(gpio->usDataY_RegisterIndex) * 4;
531 		gGPIOInfo[gpioIndex]->i2c.sclYMask = 1 << gpio->ucClkY_Shift;
532 		gGPIOInfo[gpioIndex]->i2c.sdaYMask = 1 << gpio->ucDataY_Shift;
533 
534 		// ensure data is valid
535 		gGPIOInfo[gpioIndex]->i2c.valid
536 			= gGPIOInfo[gpioIndex]->i2c.sclMaskReg ? true : false;
537 		gGPIOInfo[gpioIndex]->valid = gGPIOInfo[gpioIndex]->i2c.valid;
538 
539 		TRACE("%s: i2c GPIO @ %" B_PRIu32 ", valid: %s, hwPin: 0x%" B_PRIX32 "\n",
540 			__func__, gpioIndex, gGPIOInfo[gpioIndex]->valid ? "true" : "false",
541 			gGPIOInfo[gpioIndex]->hwPin);
542 
543 		gpioIndex++;
544 	}
545 
546 	return B_OK;
547 }
548 
549 
550 status_t
551 gpio_populate()
552 {
553 	status_t result = gpio_general_populate();
554 	if (result != B_OK)
555 		return result;
556 
557 	result = gpio_i2c_populate();
558 	return result;
559 }
560 
561 
562 status_t
563 connector_probe_legacy()
564 {
565 	int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
566 	uint8 tableMajor;
567 	uint8 tableMinor;
568 	uint16 tableSize;
569 	uint16 tableOffset;
570 
571 	if (atom_parse_data_header(gAtomContext, index, &tableSize,
572 		&tableMajor, &tableMinor, &tableOffset) != B_OK) {
573 		ERROR("%s: unable to parse data header!\n", __func__);
574 		return B_ERROR;
575 	}
576 
577 	union atomSupportedDevices {
578 		struct _ATOM_SUPPORTED_DEVICES_INFO info;
579 		struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
580 		struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
581 	};
582 	union atomSupportedDevices* supportedDevices;
583 	supportedDevices = (union atomSupportedDevices*)
584 		(gAtomContext->bios + tableOffset);
585 
586 	uint16 deviceSupport
587 		= B_LENDIAN_TO_HOST_INT16(supportedDevices->info.usDeviceSupport);
588 
589 	uint32 maxDevice;
590 
591 	if (tableMajor > 1)
592 		maxDevice = ATOM_MAX_SUPPORTED_DEVICE;
593 	else
594 		maxDevice = ATOM_MAX_SUPPORTED_DEVICE_INFO;
595 
596 	uint32 i;
597 	uint32 connectorIndex = 0;
598 	for (i = 0; i < maxDevice; i++) {
599 
600 		gConnector[connectorIndex]->valid = false;
601 
602 		// check if this connector is used
603 		if ((deviceSupport & (1 << i)) == 0)
604 			continue;
605 
606 		if (i == ATOM_DEVICE_CV_INDEX) {
607 			TRACE("%s: skipping component video\n",
608 				__func__);
609 			continue;
610 		}
611 
612 		ATOM_CONNECTOR_INFO_I2C ci
613 			= supportedDevices->info.asConnInfo[i];
614 
615 		gConnector[connectorIndex]->type = kConnectorConvertLegacy[
616 			ci.sucConnectorInfo.sbfAccess.bfConnectorType];
617 
618 		if (gConnector[connectorIndex]->type == VIDEO_CONNECTOR_UNKNOWN) {
619 			TRACE("%s: skipping unknown connector at %" B_PRId32
620 				" of 0x%" B_PRIX8 "\n", __func__, i,
621 				ci.sucConnectorInfo.sbfAccess.bfConnectorType);
622 			continue;
623 		}
624 
625 		// TODO: give tv unique connector ids
626 
627 		// Always set CRT1 and CRT2 as VGA, some cards incorrectly set
628 		// VGA ports as DVI
629 		if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
630 			gConnector[connectorIndex]->type = VIDEO_CONNECTOR_VGA;
631 
632 		uint8 dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
633 		uint32 encoderObject = encoder_object_lookup((1 << i), dac);
634 		uint32 encoderID = (encoderObject & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
635 
636 		gConnector[connectorIndex]->valid = true;
637 		gConnector[connectorIndex]->flags = (1 << i);
638 		gConnector[connectorIndex]->encoder.valid = true;
639 		gConnector[connectorIndex]->encoder.objectID = encoderID;
640 		gConnector[connectorIndex]->encoder.type
641 			= encoder_type_lookup(encoderID, (1 << i));
642 
643 		// TODO: Eval external encoders on legacy connector probe
644 		gConnector[connectorIndex]->encoderExternal.valid = false;
645 		// encoder_is_external(encoderID);
646 
647 		connector_attach_gpio_i2c(connectorIndex, ci.sucI2cId.ucAccess);
648 
649 		pll_limit_probe(&gConnector[connectorIndex]->encoder.pll);
650 
651 		connectorIndex++;
652 	}
653 
654 	// TODO: combine shared connectors
655 
656 	if (connectorIndex == 0) {
657 		TRACE("%s: zero connectors found using legacy detection\n", __func__);
658 		return B_ERROR;
659 	}
660 
661 	return B_OK;
662 }
663 
664 
665 // r600+
666 status_t
667 connector_probe()
668 {
669 	int index = GetIndexIntoMasterTable(DATA, Object_Header);
670 	uint8 tableMajor;
671 	uint8 tableMinor;
672 	uint16 tableSize;
673 	uint16 tableOffset;
674 
675 	if (atom_parse_data_header(gAtomContext, index, &tableSize,
676 		&tableMajor, &tableMinor, &tableOffset) != B_OK) {
677 		ERROR("%s: ERROR: parsing data header failed!\n", __func__);
678 		return B_ERROR;
679 	}
680 
681 	if (tableMinor < 2) {
682 		ERROR("%s: ERROR: table minor version unknown! "
683 			"(%" B_PRIu8 ".%" B_PRIu8 ")\n", __func__, tableMajor, tableMinor);
684 		return B_ERROR;
685 	}
686 
687 	ATOM_CONNECTOR_OBJECT_TABLE* connectorObject;
688 	ATOM_ENCODER_OBJECT_TABLE* encoderObject;
689 	ATOM_OBJECT_TABLE* routerObject;
690 	ATOM_DISPLAY_OBJECT_PATH_TABLE* pathObject;
691 	ATOM_OBJECT_HEADER* objectHeader;
692 
693 	objectHeader = (ATOM_OBJECT_HEADER*)(gAtomContext->bios + tableOffset);
694 	pathObject = (ATOM_DISPLAY_OBJECT_PATH_TABLE*)
695 		(gAtomContext->bios + tableOffset
696 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usDisplayPathTableOffset));
697 	connectorObject = (ATOM_CONNECTOR_OBJECT_TABLE*)
698 		(gAtomContext->bios + tableOffset
699 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usConnectorObjectTableOffset));
700 	encoderObject = (ATOM_ENCODER_OBJECT_TABLE*)
701 		(gAtomContext->bios + tableOffset
702 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usEncoderObjectTableOffset));
703 	routerObject = (ATOM_OBJECT_TABLE*)
704 		(gAtomContext->bios + tableOffset
705 		+ B_LENDIAN_TO_HOST_INT16(objectHeader->usRouterObjectTableOffset));
706 	int deviceSupport = B_LENDIAN_TO_HOST_INT16(objectHeader->usDeviceSupport);
707 
708 	int pathSize = 0;
709 	int32 i = 0;
710 
711 	TRACE("%s: found %" B_PRIu8 " potential display paths.\n", __func__,
712 		pathObject->ucNumOfDispPath);
713 
714 	uint32 connectorIndex = 0;
715 	for (i = 0; i < pathObject->ucNumOfDispPath; i++) {
716 
717 		if (connectorIndex >= ATOM_MAX_SUPPORTED_DEVICE)
718 			continue;
719 
720 		uint8* address = (uint8*)pathObject->asDispPath;
721 		ATOM_DISPLAY_OBJECT_PATH* path;
722 		address += pathSize;
723 		path = (ATOM_DISPLAY_OBJECT_PATH*)address;
724 		pathSize += B_LENDIAN_TO_HOST_INT16(path->usSize);
725 
726 		uint32 connectorType;
727 		uint16 connectorFlags = B_LENDIAN_TO_HOST_INT16(path->usDeviceTag);
728 
729 		if ((deviceSupport & connectorFlags) != 0) {
730 
731 			uint16 connectorObjectID
732 				= (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
733 					& OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
734 			//uint8 con_obj_num
735 			//	= (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
736 			//	& ENUM_ID_MASK) >> ENUM_ID_SHIFT;
737 			//uint8 con_obj_type
738 			//	= (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
739 			//	& OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
740 
741 			if (connectorFlags == ATOM_DEVICE_CV_SUPPORT) {
742 				TRACE("%s: Path #%" B_PRId32 ": skipping component video.\n",
743 					__func__, i);
744 				continue;
745 			}
746 
747 			radeon_shared_info &info = *gInfo->shared_info;
748 
749 			uint16 igpLaneInfo;
750 			if ((info.chipsetFlags & CHIP_IGP) != 0) {
751 				ERROR("%s: TODO: IGP chip connector detection\n", __func__);
752 				// try non-IGP method for now
753 				igpLaneInfo = 0;
754 				connectorType = kConnectorConvert[connectorObjectID];
755 			} else {
756 				igpLaneInfo = 0;
757 				connectorType = kConnectorConvert[connectorObjectID];
758 			}
759 
760 			if (connectorType == VIDEO_CONNECTOR_UNKNOWN) {
761 				ERROR("%s: Path #%" B_PRId32 ": skipping unknown connector.\n",
762 					__func__, i);
763 				continue;
764 			}
765 
766 			connector_info* connector = gConnector[connectorIndex];
767 
768 			int32 j;
769 			for (j = 0; j < ((B_LENDIAN_TO_HOST_INT16(path->usSize) - 8) / 2);
770 				j++) {
771 				//uint16 grph_obj_id
772 				//	= (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j])
773 				//	& OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
774 				//uint8 grph_obj_num
775 				//	= (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) &
776 				//	ENUM_ID_MASK) >> ENUM_ID_SHIFT;
777 				uint8 graphicObjectType
778 					= (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) &
779 					OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
780 
781 				if (graphicObjectType == GRAPH_OBJECT_TYPE_ENCODER) {
782 					// Found an encoder
783 					int32 k;
784 					for (k = 0; k < encoderObject->ucNumberOfObjects; k++) {
785 						uint16 encoderObjectRaw
786 							= B_LENDIAN_TO_HOST_INT16(
787 							encoderObject->asObjects[k].usObjectID);
788 						if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j])
789 							== encoderObjectRaw) {
790 							ATOM_COMMON_RECORD_HEADER* record
791 								= (ATOM_COMMON_RECORD_HEADER*)
792 								((uint16*)gAtomContext->bios + tableOffset
793 								+ B_LENDIAN_TO_HOST_INT16(
794 								encoderObject->asObjects[k].usRecordOffset));
795 							ATOM_ENCODER_CAP_RECORD* capRecord;
796 							uint16 caps = 0;
797 							while (record->ucRecordSize > 0
798 								&& record->ucRecordType > 0
799 								&& record->ucRecordType
800 								<= ATOM_MAX_OBJECT_RECORD_NUMBER) {
801 								switch (record->ucRecordType) {
802 									case ATOM_ENCODER_CAP_RECORD_TYPE:
803 										capRecord = (ATOM_ENCODER_CAP_RECORD*)
804 											record;
805 										caps = B_LENDIAN_TO_HOST_INT16(
806 											capRecord->usEncoderCap);
807 										break;
808 								}
809 								record = (ATOM_COMMON_RECORD_HEADER*)
810 									((char*)record + record->ucRecordSize);
811 							}
812 
813 							uint32 encoderID
814 								= (encoderObjectRaw & OBJECT_ID_MASK)
815 									>> OBJECT_ID_SHIFT;
816 
817 							uint32 encoderType = encoder_type_lookup(encoderID,
818 								connectorFlags);
819 
820 							if (encoderType == VIDEO_ENCODER_NONE) {
821 								ERROR("%s: Path #%" B_PRId32 ":"
822 									"skipping unknown encoder.\n",
823 									__func__, i);
824 								continue;
825 							}
826 
827 							encoder_info* encoder;
828 
829 							// External encoders are behind DVO or UNIPHY
830 							if (encoder_is_external(encoderID)) {
831 								encoder = &connector->encoderExternal;
832 								encoder->isExternal = true;
833 								encoder->isDPBridge
834 									= encoder_is_dp_bridge(encoderID);
835 							} else {
836 								encoder = &connector->encoder;
837 								encoder->isExternal = false;
838 								encoder->isDPBridge = false;
839 							}
840 
841 							// Set up found connector encoder generics
842 							encoder->valid = true;
843 							encoder->capabilities = caps;
844 							encoder->objectID = encoderID;
845 							encoder->type = encoderType;
846 							encoder->linkEnumeration
847 								= (encoderObjectRaw & ENUM_ID_MASK)
848 									>> ENUM_ID_SHIFT;
849 							pll_limit_probe(&encoder->pll);
850 						}
851 					}
852 					// END if object is encoder
853 				} else if (graphicObjectType == GRAPH_OBJECT_TYPE_ROUTER) {
854 					int32 k;
855 					for (k = 0; k < routerObject->ucNumberOfObjects; k++) {
856 						uint16 routerObjectID
857 							= B_LENDIAN_TO_HOST_INT16(routerObject->asObjects[k].usObjectID);
858 						if (B_LENDIAN_TO_HOST_INT16(path->usGraphicObjIds[j]) == routerObjectID) {
859 							ATOM_COMMON_RECORD_HEADER* record = (ATOM_COMMON_RECORD_HEADER*)
860 								((uint16*)gAtomContext->bios + tableOffset
861 								+ B_LENDIAN_TO_HOST_INT16(
862 								routerObject->asObjects[k].usRecordOffset));
863 							ATOM_I2C_RECORD* i2cRecord;
864 							ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig;
865 							ATOM_ROUTER_DDC_PATH_SELECT_RECORD* ddcPath;
866 							ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD* cdPath;
867 							ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT* routerConnTable =
868 								(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
869 								((uint16*)gAtomContext->bios + tableOffset +
870 								+ B_LENDIAN_TO_HOST_INT16(
871 								routerObject->asObjects[k].usSrcDstTableOffset));
872 							uint8* destObjCount = (uint8*)((uint8*)routerConnTable + 1
873 								+ (routerConnTable->ucNumberOfSrc * 2));
874 							uint16 *dstObjs = (uint16 *)(destObjCount + 1);
875 
876 							int enumId;
877 							router_info* router = &connector->router;
878 							router->objectID = routerObjectID;
879 							for (enumId = 0; enumId < (*destObjCount); enumId++) {
880 								if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId) ==
881 									B_LENDIAN_TO_HOST_INT16(dstObjs[enumId]))
882 									break;
883 							}
884 							while (record->ucRecordSize > 0 &&
885 								record->ucRecordType > 0 &&
886 								record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
887 								switch (record->ucRecordType) {
888 									case ATOM_I2C_RECORD_TYPE:
889 										i2cRecord = (ATOM_I2C_RECORD*)record;
890 										i2cConfig
891 											= (ATOM_I2C_ID_CONFIG_ACCESS*)&i2cRecord->sucI2cId;
892 										connector_attach_gpio_router(connectorIndex,
893 											i2cConfig->ucAccess);
894 										router->i2cAddr = i2cRecord->ucI2CAddr >> 1; // ??
895 										break;
896 									case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
897 										ddcPath = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD*)record;
898 										router->ddcValid = true;
899 										router->ddcMuxType = ddcPath->ucMuxType;
900 										router->ddcMuxControlPin = ddcPath->ucMuxControlPin;
901 										router->ddcMuxState = ddcPath->ucMuxState[enumId];
902 										break;
903 									case ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE:
904 										cdPath
905 											= (ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD *)record;
906 										router->cdValid = true;
907 										router->cdMuxType = cdPath->ucMuxType;
908 										router->cdMuxControlPin = cdPath->ucMuxControlPin;
909 										router->cdMuxState = cdPath->ucMuxState[enumId];
910 										break;
911 								}
912 
913 								// move to next record
914 								record = (ATOM_COMMON_RECORD_HEADER*)
915 									((char *)record + record->ucRecordSize);
916 							}
917 						}
918 					}
919 				} // END if object is router
920 			}
921 
922 			// Set up information buses such as ddc
923 			if (((connectorFlags & ATOM_DEVICE_TV_SUPPORT) == 0)
924 				&& (connectorFlags & ATOM_DEVICE_CV_SUPPORT) == 0) {
925 				for (j = 0; j < connectorObject->ucNumberOfObjects; j++) {
926 					if (B_LENDIAN_TO_HOST_INT16(path->usConnObjectId)
927 						== B_LENDIAN_TO_HOST_INT16(
928 						connectorObject->asObjects[j].usObjectID)) {
929 						ATOM_COMMON_RECORD_HEADER* record
930 							= (ATOM_COMMON_RECORD_HEADER*)(gAtomContext->bios
931 							+ tableOffset + B_LENDIAN_TO_HOST_INT16(
932 							connectorObject->asObjects[j].usRecordOffset));
933 						while (record->ucRecordSize > 0
934 							&& record->ucRecordType > 0
935 							&& record->ucRecordType
936 								<= ATOM_MAX_OBJECT_RECORD_NUMBER) {
937 							ATOM_I2C_RECORD* i2cRecord;
938 							ATOM_I2C_ID_CONFIG_ACCESS* i2cConfig;
939 							ATOM_HPD_INT_RECORD* hpdRecord;
940 
941 							switch (record->ucRecordType) {
942 								case ATOM_I2C_RECORD_TYPE:
943 									i2cRecord
944 										= (ATOM_I2C_RECORD*)record;
945 									i2cConfig
946 										= (ATOM_I2C_ID_CONFIG_ACCESS*)
947 										&i2cRecord->sucI2cId;
948 									connector_attach_gpio_i2c(connectorIndex,
949 										i2cConfig->ucAccess);
950 									break;
951 								case ATOM_HPD_INT_RECORD_TYPE:
952 									hpdRecord = (ATOM_HPD_INT_RECORD*)record;
953 									connector_attach_gpio_hpd(connectorIndex,
954 										hpdRecord->ucHPDIntGPIOID);
955 									break;
956 							}
957 
958 							// move to next record
959 							record = (ATOM_COMMON_RECORD_HEADER*)
960 								((char*)record + record->ucRecordSize);
961 						}
962 					}
963 				}
964 			}
965 
966 			connector->valid = true;
967 			connector->flags = connectorFlags;
968 			connector->type = connectorType;
969 			connector->objectID = connectorObjectID;
970 
971 			connectorIndex++;
972 		} // END for each valid connector
973 	} // end for each display path
974 
975 	return B_OK;
976 }
977 
978 
979 bool
980 connector_is_dp(uint32 connectorIndex)
981 {
982 	connector_info* connector = gConnector[connectorIndex];
983 
984 	// Traditional DisplayPort connector
985 	if (connector->type == VIDEO_CONNECTOR_DP
986 		|| connector->type == VIDEO_CONNECTOR_EDP) {
987 		return true;
988 	}
989 
990 	// DisplayPort bridge on external encoder
991 	if (connector->encoderExternal.valid == true
992 		&& connector->encoderExternal.isDPBridge == true) {
993 		return true;
994 	}
995 
996 	return false;
997 }
998 
999 
1000 void
1001 debug_connectors()
1002 {
1003 	ERROR("Currently detected connectors=============\n");
1004 	for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
1005 		if (gConnector[id]->valid == true) {
1006 			uint32 connectorType = gConnector[id]->type;
1007 			uint16 i2cPinIndex = gConnector[id]->i2cPinIndex;
1008 			uint16 hpdPinIndex = gConnector[id]->hpdPinIndex;
1009 
1010 			ERROR("Connector #%" B_PRIu32 ")\n", id);
1011 			ERROR(" + connector:          %s\n",
1012 				get_connector_name(connectorType));
1013 			ERROR(" + i2c gpio table id:  %" B_PRIu16 "\n", i2cPinIndex);
1014 			ERROR("   - gpio hw pin:      0x%" B_PRIX32 "\n",
1015 				gGPIOInfo[i2cPinIndex]->hwPin);
1016 			ERROR("   - gpio valid:       %s\n",
1017 				gGPIOInfo[i2cPinIndex]->valid ? "true" : "false");
1018 			ERROR("   - i2c valid:        %s\n",
1019 				gGPIOInfo[i2cPinIndex]->i2c.valid ? "true" : "false");
1020 
1021 			// hot plug detection info
1022 			ERROR(" + hpd gpio table id:  %" B_PRIu16 "\n", hpdPinIndex);
1023 			ERROR("   - gpio hw pin:      0x%" B_PRIX32 "\n",
1024 				 gGPIOInfo[hpdPinIndex]->hwPin);
1025 			ERROR("   - gpio valid:       %s\n",
1026 				gGPIOInfo[hpdPinIndex]->valid ? "true" : "false");
1027 
1028 			// router info
1029 			router_info* router = &gConnector[id]->router;
1030 			ERROR(" + router gpio table id: %" B_PRIu16 "\n", router->i2cPinIndex);
1031 			ERROR(" + router (ddc):       %s\n",
1032 				router->ddcValid ? "true" : "false");
1033 			if (router->ddcValid) {
1034 				ERROR("   - mux  type: 0x%" B_PRIX8 "\n", router->ddcMuxType);
1035 				ERROR("   - mux   pin: 0x%" B_PRIX8 "\n", router->ddcMuxControlPin);
1036 				ERROR("   - mux state: 0x%" B_PRIX8 "\n", router->ddcMuxState);
1037 			}
1038 			ERROR(" + router (c/d):       %s\n",
1039 				router->cdValid ? "true" : "false");
1040 			if (router->cdValid) {
1041 				ERROR("   - mux  type: 0x%" B_PRIX8 "\n", router->cdMuxType);
1042 				ERROR("   - mux   pin: 0x%" B_PRIX8 "\n", router->cdMuxControlPin);
1043 				ERROR("   - mux state: 0x%" B_PRIX8 "\n", router->cdMuxState);
1044 			}
1045 
1046 			// encoder info
1047 			encoder_info* encoder = &gConnector[id]->encoder;
1048 			ERROR(" + encoder:            %s\n",
1049 				get_encoder_name(encoder->type));
1050 			ERROR("   - id:               %" B_PRIu16 "\n", encoder->objectID);
1051 			ERROR("   - type:             %s\n",
1052 				encoder_name_lookup(encoder->objectID));
1053 			ERROR("   - capabilities:     0x%" B_PRIX32 "\n",
1054 				encoder->capabilities);
1055 			ERROR("   - enumeration:      %" B_PRIu32 "\n",
1056 				encoder->linkEnumeration);
1057 
1058 			encoder = &gConnector[id]->encoderExternal;
1059 
1060 			ERROR("   - is bridge:        %s\n",
1061 				encoder->valid ? "true" : "false");
1062 
1063 			if (!encoder->valid)
1064 				ERROR("   + external encoder: none\n");
1065 			else {
1066 			ERROR("   + external encoder: %s\n",
1067 					get_encoder_name(encoder->type));
1068 				ERROR("     - valid:          true\n");
1069 				ERROR("     - id:             %" B_PRIu16 "\n",
1070 					encoder->objectID);
1071 				ERROR("     - type:           %s\n",
1072 					encoder_name_lookup(encoder->objectID));
1073 				ERROR("     - enumeration:    %" B_PRIu32 "\n",
1074 					encoder->linkEnumeration);
1075 			}
1076 
1077 			uint32 connectorFlags = gConnector[id]->flags;
1078 			bool flags = false;
1079 			ERROR(" + flags:\n");
1080 			if ((connectorFlags & ATOM_DEVICE_CRT1_SUPPORT) != 0) {
1081 				ERROR("   * device CRT1 support\n");
1082 				flags = true;
1083 			}
1084 			if ((connectorFlags & ATOM_DEVICE_CRT2_SUPPORT) != 0) {
1085 				ERROR("   * device CRT2 support\n");
1086 				flags = true;
1087 			}
1088 			if ((connectorFlags & ATOM_DEVICE_LCD1_SUPPORT) != 0) {
1089 				ERROR("   * device LCD1 support\n");
1090 				flags = true;
1091 			}
1092 			if ((connectorFlags & ATOM_DEVICE_LCD2_SUPPORT) != 0) {
1093 				ERROR("   * device LCD2 support\n");
1094 				flags = true;
1095 			}
1096 			if ((connectorFlags & ATOM_DEVICE_TV1_SUPPORT) != 0) {
1097 				ERROR("   * device TV1 support\n");
1098 				flags = true;
1099 			}
1100 			if ((connectorFlags & ATOM_DEVICE_CV_SUPPORT) != 0) {
1101 				ERROR("   * device CV support\n");
1102 				flags = true;
1103 			}
1104 			if ((connectorFlags & ATOM_DEVICE_DFP1_SUPPORT) != 0) {
1105 				ERROR("   * device DFP1 support\n");
1106 				flags = true;
1107 			}
1108 			if ((connectorFlags & ATOM_DEVICE_DFP2_SUPPORT) != 0) {
1109 				ERROR("   * device DFP2 support\n");
1110 				flags = true;
1111 			}
1112 			if ((connectorFlags & ATOM_DEVICE_DFP3_SUPPORT) != 0) {
1113 				ERROR("   * device DFP3 support\n");
1114 				flags = true;
1115 			}
1116 			if ((connectorFlags & ATOM_DEVICE_DFP4_SUPPORT) != 0) {
1117 				ERROR("   * device DFP4 support\n");
1118 				flags = true;
1119 			}
1120 			if ((connectorFlags & ATOM_DEVICE_DFP5_SUPPORT) != 0) {
1121 				ERROR("   * device DFP5 support\n");
1122 				flags = true;
1123 			}
1124 			if ((connectorFlags & ATOM_DEVICE_DFP6_SUPPORT) != 0) {
1125 				ERROR("   * device DFP6 support\n");
1126 				flags = true;
1127 			}
1128 			if (flags == false)
1129 				ERROR("   * no known flags\n");
1130 		}
1131 	}
1132 	ERROR("==========================================\n");
1133 }
1134