Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 43a23aa4 authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/radeon: properly validate the atpx interface

Some bioses don't set the function mask correctly
which caused required functions to be disabled.

Fixes:
https://bugzilla.kernel.org/show_bug.cgi?id=53111



Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
parent d0418894
Loading
Loading
Loading
Loading
+71 −2
Original line number Diff line number Diff line
@@ -43,6 +43,12 @@ struct atpx_verify_interface {
	u32 function_bits;	/* supported functions bit vector */
} __packed;

struct atpx_px_params {
	u16 size;		/* structure size in bytes (includes size field) */
	u32 valid_flags;	/* which flags are valid */
	u32 flags;		/* flags */
} __packed;

struct atpx_power_control {
	u16 size;
	u8 dgpu_state;
@@ -122,10 +128,62 @@ static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mas
	f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED;
}

/**
 * radeon_atpx_validate_functions - validate ATPX functions
 *
 * @atpx: radeon atpx struct
 *
 * Validate that required functions are enabled (all asics).
 * returns 0 on success, error on failure.
 */
static int radeon_atpx_validate(struct radeon_atpx *atpx)
{
	/* make sure required functions are enabled */
	/* dGPU power control is required */
	atpx->functions.power_cntl = true;

	if (atpx->functions.px_params) {
		union acpi_object *info;
		struct atpx_px_params output;
		size_t size;
		u32 valid_bits;

		info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_GET_PX_PARAMETERS, NULL);
		if (!info)
			return -EIO;

		memset(&output, 0, sizeof(output));

		size = *(u16 *) info->buffer.pointer;
		if (size < 10) {
			printk("ATPX buffer is too small: %zu\n", size);
			kfree(info);
			return -EINVAL;
		}
		size = min(sizeof(output), size);

		memcpy(&output, info->buffer.pointer, size);

		valid_bits = output.flags & output.valid_flags;
		/* if separate mux flag is set, mux controls are required */
		if (valid_bits & ATPX_SEPARATE_MUX_FOR_I2C) {
			atpx->functions.i2c_mux_cntl = true;
			atpx->functions.disp_mux_cntl = true;
		}
		/* if any outputs are muxed, mux controls are required */
		if (valid_bits & (ATPX_CRT1_RGB_SIGNAL_MUXED |
				  ATPX_TV_SIGNAL_MUXED |
				  ATPX_DFP_SIGNAL_MUXED))
			atpx->functions.disp_mux_cntl = true;

		kfree(info);
	}
	return 0;
}

/**
 * radeon_atpx_verify_interface - verify ATPX
 *
 * @handle: acpi handle
 * @atpx: radeon atpx struct
 *
 * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function
@@ -406,8 +464,19 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
 */
static int radeon_atpx_init(void)
{
	int r;

	/* set up the ATPX handle */
	return radeon_atpx_verify_interface(&radeon_atpx_priv.atpx);
	r = radeon_atpx_verify_interface(&radeon_atpx_priv.atpx);
	if (r)
		return r;

	/* validate the atpx setup */
	r = radeon_atpx_validate(&radeon_atpx_priv.atpx);
	if (r)
		return r;

	return 0;
}

/**