drm/nouveau: support fetching LVDS EDID from ACPI
Based on a patch from Matthew Garrett. Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Acked-by: Matthew Garrett <mjg@redhat.com>
This commit is contained in:
parent
03639b5038
commit
a6ed76d7ff
@ -3,6 +3,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/video.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
@ -11,6 +12,7 @@
|
||||
#include "nouveau_drv.h"
|
||||
#include "nouveau_drm.h"
|
||||
#include "nv50_display.h"
|
||||
#include "nouveau_connector.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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -5622,7 +5622,9 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
|
||||
if (conf & 0x4 || conf & 0x8)
|
||||
entry->lvdsconf.use_power_scripts = true;
|
||||
} else {
|
||||
mask = ~0x5;
|
||||
mask = ~0x7;
|
||||
if (conf & 0x2)
|
||||
entry->lvdsconf.use_acpi_for_edid = true;
|
||||
if (conf & 0x4)
|
||||
entry->lvdsconf.use_power_scripts = true;
|
||||
}
|
||||
|
@ -118,6 +118,7 @@ struct dcb_entry {
|
||||
struct {
|
||||
struct sor_conf sor;
|
||||
bool use_straps_for_mode;
|
||||
bool use_acpi_for_edid;
|
||||
bool use_power_scripts;
|
||||
} lvdsconf;
|
||||
struct {
|
||||
|
@ -327,12 +327,29 @@ nouveau_connector_detect_lvds(struct drm_connector *connector)
|
||||
if (!nv_encoder)
|
||||
return connector_status_disconnected;
|
||||
|
||||
/* Try retrieving EDID via DDC */
|
||||
if (!dev_priv->vbios.fp_no_ddc) {
|
||||
status = nouveau_connector_detect(connector);
|
||||
if (status == connector_status_connected)
|
||||
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
|
||||
* modeline is avalilable for the panel, set it as the panel's
|
||||
* native mode and exit.
|
||||
|
@ -827,11 +827,13 @@ void nouveau_register_dsm_handler(void);
|
||||
void nouveau_unregister_dsm_handler(void);
|
||||
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
|
||||
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
|
||||
int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
|
||||
#else
|
||||
static inline void nouveau_register_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 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
|
||||
|
||||
/* nouveau_backlight.c */
|
||||
|
Loading…
Reference in New Issue
Block a user