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

Commit a6ed76d7 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau: support fetching LVDS EDID from ACPI



Based on a patch from Matthew Garrett.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Acked-by: default avatarMatthew Garrett <mjg@redhat.com>
parent 03639b50
Loading
Loading
Loading
Loading
+36 −0
Original line number Original line Diff line number Diff line
@@ -3,6 +3,7 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_bus.h>
#include <acpi/video.h>


#include "drmP.h"
#include "drmP.h"
#include "drm.h"
#include "drm.h"
@@ -11,6 +12,7 @@
#include "nouveau_drv.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nouveau_drm.h"
#include "nv50_display.h"
#include "nv50_display.h"
#include "nouveau_connector.h"


#include <linux/vga_switcheroo.h>
#include <linux/vga_switcheroo.h>


@@ -259,3 +261,37 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
{
{
	return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
	return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
}
}

int
nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
{
	struct nouveau_connector *nv_connector = nouveau_connector(connector);
	struct acpi_device *acpidev;
	acpi_handle handle;
	int type, ret;
	void *edid;

	switch (connector->connector_type) {
	case DRM_MODE_CONNECTOR_LVDS:
	case DRM_MODE_CONNECTOR_eDP:
		type = ACPI_VIDEO_DISPLAY_LCD;
		break;
	default:
		return -EINVAL;
	}

	handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
	if (!handle)
		return -ENODEV;

	ret = acpi_bus_get_device(handle, &acpidev);
	if (ret)
		return -ENODEV;

	ret = acpi_video_get_edid(acpidev, type, -1, &edid);
	if (ret < 0)
		return ret;

	nv_connector->edid = edid;
	return 0;
}
+3 −1
Original line number Original line Diff line number Diff line
@@ -5622,7 +5622,9 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
			if (conf & 0x4 || conf & 0x8)
			if (conf & 0x4 || conf & 0x8)
				entry->lvdsconf.use_power_scripts = true;
				entry->lvdsconf.use_power_scripts = true;
		} else {
		} else {
			mask = ~0x5;
			mask = ~0x7;
			if (conf & 0x2)
				entry->lvdsconf.use_acpi_for_edid = true;
			if (conf & 0x4)
			if (conf & 0x4)
				entry->lvdsconf.use_power_scripts = true;
				entry->lvdsconf.use_power_scripts = true;
		}
		}
+1 −0
Original line number Original line Diff line number Diff line
@@ -118,6 +118,7 @@ struct dcb_entry {
		struct {
		struct {
			struct sor_conf sor;
			struct sor_conf sor;
			bool use_straps_for_mode;
			bool use_straps_for_mode;
			bool use_acpi_for_edid;
			bool use_power_scripts;
			bool use_power_scripts;
		} lvdsconf;
		} lvdsconf;
		struct {
		struct {
+17 −0
Original line number Original line Diff line number Diff line
@@ -327,12 +327,29 @@ nouveau_connector_detect_lvds(struct drm_connector *connector)
	if (!nv_encoder)
	if (!nv_encoder)
		return connector_status_disconnected;
		return connector_status_disconnected;


	/* Try retrieving EDID via DDC */
	if (!dev_priv->vbios.fp_no_ddc) {
	if (!dev_priv->vbios.fp_no_ddc) {
		status = nouveau_connector_detect(connector);
		status = nouveau_connector_detect(connector);
		if (status == connector_status_connected)
		if (status == connector_status_connected)
			goto out;
			goto out;
	}
	}


	/* On some laptops (Sony, i'm looking at you) there appears to
	 * be no direct way of accessing the panel's EDID.  The only
	 * option available to us appears to be to ask ACPI for help..
	 *
	 * It's important this check's before trying straps, one of the
	 * said manufacturer's laptops are configured in such a way
	 * the nouveau decides an entry in the VBIOS FP mode table is
	 * valid - it's not (rh#613284)
	 */
	if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
		if (!nouveau_acpi_edid(dev, connector)) {
			status = connector_status_connected;
			goto out;
		}
	}

	/* If no EDID found above, and the VBIOS indicates a hardcoded
	/* If no EDID found above, and the VBIOS indicates a hardcoded
	 * modeline is avalilable for the panel, set it as the panel's
	 * modeline is avalilable for the panel, set it as the panel's
	 * native mode and exit.
	 * native mode and exit.
+2 −0
Original line number Original line Diff line number Diff line
@@ -827,11 +827,13 @@ void nouveau_register_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
#else
#else
static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
static inline int nouveau_acpi_edid(struct drm_device *, struct drm_connector *) { return -EINVAL; }
#endif
#endif


/* nouveau_backlight.c */
/* nouveau_backlight.c */