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
35static void
36gpio_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
86static status_t
87gpio_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
101static status_t
102gpio_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
120uint16
121connector_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
174bool
175connector_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
207bool
208connector_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
308static status_t
309connector_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
326static status_t
327connector_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
345static status_t
346gpio_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
405static status_t
406gpio_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
530status_t
531gpio_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
542status_t
543connector_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+
646status_t
647connector_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
895bool
896connector_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
916void
917debug_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