diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_opregion.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_opregion.c | 139 | 
1 files changed, 45 insertions, 94 deletions
| diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 7acbbbf97833..f4429f67a4e3 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -642,24 +642,6 @@ static struct notifier_block intel_opregion_notifier = {   * (version 3)   */ -static u32 get_did(struct intel_opregion *opregion, int i) -{ -	u32 did; - -	if (i < ARRAY_SIZE(opregion->acpi->didl)) { -		did = opregion->acpi->didl[i]; -	} else { -		i -= ARRAY_SIZE(opregion->acpi->didl); - -		if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2))) -			return 0; - -		did = opregion->acpi->did2[i]; -	} - -	return did; -} -  static void set_did(struct intel_opregion *opregion, int i, u32 val)  {  	if (i < ARRAY_SIZE(opregion->acpi->didl)) { @@ -674,11 +656,11 @@ static void set_did(struct intel_opregion *opregion, int i, u32 val)  	}  } -static u32 acpi_display_type(struct drm_connector *connector) +static u32 acpi_display_type(struct intel_connector *connector)  {  	u32 display_type; -	switch (connector->connector_type) { +	switch (connector->base.connector_type) {  	case DRM_MODE_CONNECTOR_VGA:  	case DRM_MODE_CONNECTOR_DVIA:  		display_type = ACPI_DISPLAY_TYPE_VGA; @@ -707,7 +689,7 @@ static u32 acpi_display_type(struct drm_connector *connector)  		display_type = ACPI_DISPLAY_TYPE_OTHER;  		break;  	default: -		MISSING_CASE(connector->connector_type); +		MISSING_CASE(connector->base.connector_type);  		display_type = ACPI_DISPLAY_TYPE_OTHER;  		break;  	} @@ -718,34 +700,9 @@ static u32 acpi_display_type(struct drm_connector *connector)  static void intel_didl_outputs(struct drm_i915_private *dev_priv)  {  	struct intel_opregion *opregion = &dev_priv->opregion; -	struct pci_dev *pdev = dev_priv->drm.pdev; -	struct drm_connector *connector; -	acpi_handle handle; -	struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; -	unsigned long long device_id; -	acpi_status status; -	u32 temp, max_outputs; -	int i = 0; - -	handle = ACPI_HANDLE(&pdev->dev); -	if (!handle || acpi_bus_get_device(handle, &acpi_dev)) -		return; - -	if (acpi_is_video_device(handle)) -		acpi_video_bus = acpi_dev; -	else { -		list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { -			if (acpi_is_video_device(acpi_cdev->handle)) { -				acpi_video_bus = acpi_cdev; -				break; -			} -		} -	} - -	if (!acpi_video_bus) { -		DRM_DEBUG_KMS("No ACPI video bus found\n"); -		return; -	} +	struct intel_connector *connector; +	int i = 0, max_outputs; +	int display_index[16] = {};  	/*  	 * In theory, did2, the extended didl, gets added at opregion version @@ -757,64 +714,58 @@ static void intel_didl_outputs(struct drm_i915_private *dev_priv)  	max_outputs = ARRAY_SIZE(opregion->acpi->didl) +  		ARRAY_SIZE(opregion->acpi->did2); -	list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { -		if (i >= max_outputs) { -			DRM_DEBUG_KMS("More than %u outputs detected via ACPI\n", -				      max_outputs); -			return; -		} -		status = acpi_evaluate_integer(acpi_cdev->handle, "_ADR", -					       NULL, &device_id); -		if (ACPI_SUCCESS(status)) { -			if (!device_id) -				goto blind_set; -			set_did(opregion, i++, (u32)(device_id & 0x0f0f)); -		} +	for_each_intel_connector(&dev_priv->drm, connector) { +		u32 device_id, type; + +		device_id = acpi_display_type(connector); + +		/* Use display type specific display index. */ +		type = (device_id & ACPI_DISPLAY_TYPE_MASK) +			>> ACPI_DISPLAY_TYPE_SHIFT; +		device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT; + +		connector->acpi_device_id = device_id; +		if (i < max_outputs) +			set_did(opregion, i, device_id); +		i++;  	} -end:  	DRM_DEBUG_KMS("%d outputs detected\n", i); +	if (i > max_outputs) +		DRM_ERROR("More than %d outputs in connector list\n", +			  max_outputs); +  	/* If fewer than max outputs, the list must be null terminated */  	if (i < max_outputs)  		set_did(opregion, i, 0); -	return; - -blind_set: -	i = 0; -	list_for_each_entry(connector, -			    &dev_priv->drm.mode_config.connector_list, head) { -		int display_type = acpi_display_type(connector); - -		if (i >= max_outputs) { -			DRM_DEBUG_KMS("More than %u outputs in connector list\n", -				      max_outputs); -			return; -		} - -		temp = get_did(opregion, i); -		set_did(opregion, i, temp | (1 << 31) | display_type | i); -		i++; -	} -	goto end;  }  static void intel_setup_cadls(struct drm_i915_private *dev_priv)  {  	struct intel_opregion *opregion = &dev_priv->opregion; +	struct intel_connector *connector;  	int i = 0; -	u32 disp_id; - -	/* Initialize the CADL field by duplicating the DIDL values. -	 * Technically, this is not always correct as display outputs may exist, -	 * but not active. This initialization is necessary for some Clevo -	 * laptops that check this field before processing the brightness and -	 * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if -	 * there are less than eight devices. */ -	do { -		disp_id = get_did(opregion, i); -		opregion->acpi->cadl[i] = disp_id; -	} while (++i < 8 && disp_id != 0); + +	/* +	 * Initialize the CADL field from the connector device ids. This is +	 * essentially the same as copying from the DIDL. Technically, this is +	 * not always correct as display outputs may exist, but not active. This +	 * initialization is necessary for some Clevo laptops that check this +	 * field before processing the brightness and display switching hotkeys. +	 * +	 * Note that internal panels should be at the front of the connector +	 * list already, ensuring they're not left out. +	 */ +	for_each_intel_connector(&dev_priv->drm, connector) { +		if (i >= ARRAY_SIZE(opregion->acpi->cadl)) +			break; +		opregion->acpi->cadl[i++] = connector->acpi_device_id; +	} + +	/* If fewer than 8 active devices, the list must be null terminated */ +	if (i < ARRAY_SIZE(opregion->acpi->cadl)) +		opregion->acpi->cadl[i] = 0;  }  void intel_opregion_register(struct drm_i915_private *dev_priv) |