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