Opened 7 weeks ago

Last modified 7 weeks ago

#15044 new bug

Radeon RX Vega M GH: Monitor going out of sync.

Reported by: bga Owned by: kallisti5
Priority: normal Milestone: Unscheduled
Component: Drivers/Graphics/radeon_hd Version: R1/Development
Keywords: Cc:
Blocked By: Blocking:
Has a Patch: no Platform: All

Description

I have a NUC 8 computer that has the card mentioned in the summary. The PCI ID (0x694c) was not present in the existing driver so I added it:

diff --git a/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp
index 6e00eb6511..a7ccd6ef3c 100644
--- a/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp
+++ b/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp
@@ -544,7 +544,8 @@ const struct supported_device {
        {0x6867, 13, 0, RADEON_VEGA, CHIP_STD, "Radeon RX Vega 56"},
        {0x687f, 13, 0, RADEON_VEGA, CHIP_STD, "Radeon RX Vega 64"},
        {0x684c, 13, 0, RADEON_VEGA, CHIP_STD, "Radeon RX Vega M GH"},
-       {0x684e, 13, 0, RADEON_VEGA, CHIP_STD, "Radeon RX Vega M GL"}
+       {0x684e, 13, 0, RADEON_VEGA, CHIP_STD, "Radeon RX Vega M GL"},
+       {0x694c, 13, 0, RADEON_VEGA, CHIP_STD, "Radeon RX Vega M GH"}
 };

The driver then detects and tries to initialize the graphics card, but my monitor goes out of sync.

Attached is the radeon_hd information from syslog (from the point it detected the monitor connected to the HDMI port to when log information for radeon_hd finished. Let me know if you need the log before that too).

In case it matters, the monitor is connected to the computer through a KVM (but the KVM has EDID emulation so it should not be an issue and works with other OSs).

Let me kinow if you need more information.

Attachments (1)

radeon_hd (28.1 KB) - added by bga 7 weeks ago.
radeon_hd partial syslog

Download all attachments as: .zip

Change History (10)

Changed 7 weeks ago by bga

Attachment: radeon_hd added

radeon_hd partial syslog

comment:1 Changed 7 weeks ago by bga

Forgot to include at least the basic monitor information. Sorry.

Monitor has a maximum resolution of 4k@30Hz. All other resolutions are locked to 60Hz.

comment:2 Changed 7 weeks ago by bga

I connected the monitor directly to the computer (bypassing the KVM). Same issue.

comment:3 Changed 7 weeks ago by kallisti5

Ah, I don't have any Vega cards to test here. However, this is the most telling part:

WARNING: CHECK NEW DCE mmDC_GPIO_HPD_A value!

That warning means the accelerant has detected an unknown define/instruction coming from the AtomBIOS on the card.

Someone likely needs to look at the linux drm code for radeon_hd and see what additions have been made around mmDC_GPIO_HPD_A or in the AtomBIOS headers.

comment:5 Changed 7 weeks ago by bga

Hmmm, that patchset only seems to define mmDC_GPIO_HPD_A, but I can not find it being used anywhere.

comment:6 Changed 7 weeks ago by bga

In case it might be helpful somehow:

#define mmDC_GPIO_HPD_A 0x488d

comment:7 Changed 7 weeks ago by bga

Or maybe this?

https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_translate_dce110.c#L77

static bool offset_to_id(
	uint32_t offset,
	uint32_t mask,
	enum gpio_id *id,
	uint32_t *en)
{
	switch (offset) {
	/* GENERIC */
	case mmDC_GPIO_GENERIC_A:
		*id = GPIO_ID_GENERIC;
		switch (mask) {
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK:
			*en = GPIO_GENERIC_A;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK:
			*en = GPIO_GENERIC_B;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK:
			*en = GPIO_GENERIC_C;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK:
			*en = GPIO_GENERIC_D;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK:
			*en = GPIO_GENERIC_E;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK:
			*en = GPIO_GENERIC_F;
			return true;
		case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK:
			*en = GPIO_GENERIC_G;
			return true;
		default:
			ASSERT_CRITICAL(false);
			return false;
		}
	break;
	/* HPD */
	case mmDC_GPIO_HPD_A:
		*id = GPIO_ID_HPD;
		switch (mask) {
		case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK:
			*en = GPIO_HPD_1;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK:
			*en = GPIO_HPD_2;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK:
			*en = GPIO_HPD_3;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK:
			*en = GPIO_HPD_4;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK:
			*en = GPIO_HPD_5;
			return true;
		case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK:
			*en = GPIO_HPD_6;
			return true;
		default:
			ASSERT_CRITICAL(false);
			return false;
		}
	break;
	/* SYNCA */
	case mmDC_GPIO_SYNCA_A:
		*id = GPIO_ID_SYNC;
		switch (mask) {
		case DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK:
			*en = GPIO_SYNC_HSYNC_A;
			return true;
		case DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK:
			*en = GPIO_SYNC_VSYNC_A;
			return true;
		default:
			ASSERT_CRITICAL(false);
			return false;
		}
	break;
	/* mmDC_GPIO_GENLK_MASK */
	case mmDC_GPIO_GENLK_A:
		*id = GPIO_ID_GSL;
		switch (mask) {
		case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK:
			*en = GPIO_GSL_GENLOCK_CLOCK;
			return true;
		case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK:
			*en = GPIO_GSL_GENLOCK_VSYNC;
			return true;
		case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK:
			*en = GPIO_GSL_SWAPLOCK_A;
			return true;
		case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK:
			*en = GPIO_GSL_SWAPLOCK_B;
			return true;
		default:
			ASSERT_CRITICAL(false);
			return false;
		}
	break;
	/* DDC */
	/* we don't care about the GPIO_ID for DDC
	 * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK
	 * directly in the create method */
	case mmDC_GPIO_DDC1_A:
		*en = GPIO_DDC_LINE_DDC1;
		return true;
	case mmDC_GPIO_DDC2_A:
		*en = GPIO_DDC_LINE_DDC2;
		return true;
	case mmDC_GPIO_DDC3_A:
		*en = GPIO_DDC_LINE_DDC3;
		return true;
	case mmDC_GPIO_DDC4_A:
		*en = GPIO_DDC_LINE_DDC4;
		return true;
	case mmDC_GPIO_DDC5_A:
		*en = GPIO_DDC_LINE_DDC5;
		return true;
	case mmDC_GPIO_DDC6_A:
		*en = GPIO_DDC_LINE_DDC6;
		return true;
	case mmDC_GPIO_DDCVGA_A:
		*en = GPIO_DDC_LINE_DDC_VGA;
		return true;
	/* GPIO_I2CPAD */
	case mmDC_GPIO_I2CPAD_A:
		*en = GPIO_DDC_LINE_I2C_PAD;
		return true;
	/* Not implemented */
	case mmDC_GPIO_PWRSEQ_A:
	case mmDC_GPIO_PAD_STRENGTH_1:
	case mmDC_GPIO_PAD_STRENGTH_2:
	case mmDC_GPIO_DEBUG:
		return false;
	/* UNEXPECTED */
	default:
		ASSERT_CRITICAL(false);
		return false;
	}
}

And this:

static bool id_to_offset(
	enum gpio_id id,
	uint32_t en,
	struct gpio_pin_info *info)
{
	bool result = true;

	switch (id) {
	case GPIO_ID_DDC_DATA:
		info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK;
		switch (en) {
		case GPIO_DDC_LINE_DDC1:
			info->offset = mmDC_GPIO_DDC1_A;
		break;
		case GPIO_DDC_LINE_DDC2:
			info->offset = mmDC_GPIO_DDC2_A;
		break;
		case GPIO_DDC_LINE_DDC3:
			info->offset = mmDC_GPIO_DDC3_A;
		break;
		case GPIO_DDC_LINE_DDC4:
			info->offset = mmDC_GPIO_DDC4_A;
		break;
		case GPIO_DDC_LINE_DDC5:
			info->offset = mmDC_GPIO_DDC5_A;
		break;
		case GPIO_DDC_LINE_DDC6:
			info->offset = mmDC_GPIO_DDC6_A;
		break;
		case GPIO_DDC_LINE_DDC_VGA:
			info->offset = mmDC_GPIO_DDCVGA_A;
		break;
		case GPIO_DDC_LINE_I2C_PAD:
			info->offset = mmDC_GPIO_I2CPAD_A;
		break;
		default:
			ASSERT_CRITICAL(false);
			result = false;
		}
	break;
	case GPIO_ID_DDC_CLOCK:
		info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK;
		switch (en) {
		case GPIO_DDC_LINE_DDC1:
			info->offset = mmDC_GPIO_DDC1_A;
		break;
		case GPIO_DDC_LINE_DDC2:
			info->offset = mmDC_GPIO_DDC2_A;
		break;
		case GPIO_DDC_LINE_DDC3:
			info->offset = mmDC_GPIO_DDC3_A;
		break;
		case GPIO_DDC_LINE_DDC4:
			info->offset = mmDC_GPIO_DDC4_A;
		break;
		case GPIO_DDC_LINE_DDC5:
			info->offset = mmDC_GPIO_DDC5_A;
		break;
		case GPIO_DDC_LINE_DDC6:
			info->offset = mmDC_GPIO_DDC6_A;
		break;
		case GPIO_DDC_LINE_DDC_VGA:
			info->offset = mmDC_GPIO_DDCVGA_A;
		break;
		case GPIO_DDC_LINE_I2C_PAD:
			info->offset = mmDC_GPIO_I2CPAD_A;
		break;
		default:
			ASSERT_CRITICAL(false);
			result = false;
		}
	break;
	case GPIO_ID_GENERIC:
		info->offset = mmDC_GPIO_GENERIC_A;
		switch (en) {
		case GPIO_GENERIC_A:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK;
		break;
		case GPIO_GENERIC_B:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK;
		break;
		case GPIO_GENERIC_C:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK;
		break;
		case GPIO_GENERIC_D:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK;
		break;
		case GPIO_GENERIC_E:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK;
		break;
		case GPIO_GENERIC_F:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK;
		break;
		case GPIO_GENERIC_G:
			info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK;
		break;
		default:
			ASSERT_CRITICAL(false);
			result = false;
		}
	break;
	case GPIO_ID_HPD:
		info->offset = mmDC_GPIO_HPD_A;
		switch (en) {
		case GPIO_HPD_1:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK;
		break;
		case GPIO_HPD_2:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK;
		break;
		case GPIO_HPD_3:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK;
		break;
		case GPIO_HPD_4:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK;
		break;
		case GPIO_HPD_5:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK;
		break;
		case GPIO_HPD_6:
			info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK;
		break;
		default:
			ASSERT_CRITICAL(false);
			result = false;
		}
	break;
	case GPIO_ID_SYNC:
		switch (en) {
		case GPIO_SYNC_HSYNC_A:
			info->offset = mmDC_GPIO_SYNCA_A;
			info->mask = DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK;
		break;
		case GPIO_SYNC_VSYNC_A:
			info->offset = mmDC_GPIO_SYNCA_A;
			info->mask = DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK;
		break;
		case GPIO_SYNC_HSYNC_B:
		case GPIO_SYNC_VSYNC_B:
		default:
			ASSERT_CRITICAL(false);
			result = false;
		}
	break;
	case GPIO_ID_GSL:
		switch (en) {
		case GPIO_GSL_GENLOCK_CLOCK:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask = DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK;
		break;
		case GPIO_GSL_GENLOCK_VSYNC:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask =
				DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK;
		break;
		case GPIO_GSL_SWAPLOCK_A:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK;
		break;
		case GPIO_GSL_SWAPLOCK_B:
			info->offset = mmDC_GPIO_GENLK_A;
			info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK;
		break;
		default:
			ASSERT_CRITICAL(false);
			result = false;
		}
	break;
	case GPIO_ID_VIP_PAD:
	default:
		ASSERT_CRITICAL(false);
		result = false;
	}

	if (result) {
		info->offset_y = info->offset + 2;
		info->offset_en = info->offset + 1;
		info->offset_mask = info->offset - 1;

		info->mask_y = info->mask;
		info->mask_en = info->mask;
		info->mask_mask = info->mask;
	}

	return result;
}

If you have any ideas about what these are doing and how to do the same in the Haiku radeon driver, I can give it a go *although it would be mostly cargo-cult).

comment:9 Changed 7 weeks ago by bga

Also, the Linux considers this card to be a VEGAM. In case it matters, here are all references to VEGAM:

https://github.com/torvalds/linux/search?q=VEGAM&unscoped_q=VEGAM

Note: See TracTickets for help on using tickets.