Commit a6ed76d7 authored by Ben Skeggs's avatar Ben Skeggs

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
...@@ -3,6 +3,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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;
}
...@@ -5622,7 +5622,9 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, ...@@ -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;
} }
......
...@@ -118,6 +118,7 @@ struct dcb_entry { ...@@ -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 {
......
...@@ -327,12 +327,29 @@ nouveau_connector_detect_lvds(struct drm_connector *connector) ...@@ -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.
......
...@@ -827,11 +827,13 @@ void nouveau_register_dsm_handler(void); ...@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment