diff options
Diffstat (limited to 'drivers/gpu/drm/i915/display/intel_opregion.c')
-rw-r--r-- | drivers/gpu/drm/i915/display/intel_opregion.c | 78 |
1 files changed, 62 insertions, 16 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index af9d30f56cc1..f31e8c3f8ce0 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -47,10 +47,11 @@ #define OPREGION_ASLE_EXT_OFFSET 0x1C00 #define OPREGION_SIGNATURE "IntelGraphicsMem" -#define MBOX_ACPI (1<<0) -#define MBOX_SWSCI (1<<1) -#define MBOX_ASLE (1<<2) -#define MBOX_ASLE_EXT (1<<4) +#define MBOX_ACPI BIT(0) /* Mailbox #1 */ +#define MBOX_SWSCI BIT(1) /* Mailbox #2 (obsolete from v2.x) */ +#define MBOX_ASLE BIT(2) /* Mailbox #3 */ +#define MBOX_ASLE_EXT BIT(4) /* Mailbox #5 */ +#define MBOX_BACKLIGHT BIT(5) /* Mailbox #2 (valid from v3.x) */ struct opregion_header { u8 signature[16]; @@ -245,14 +246,10 @@ struct opregion_asle_ext { #define MAX_DSLP 1500 -static int swsci(struct drm_i915_private *dev_priv, - u32 function, u32 parm, u32 *parm_out) +static int check_swsci_function(struct drm_i915_private *i915, u32 function) { - struct opregion_swsci *swsci = dev_priv->opregion.swsci; - struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - u32 main_function, sub_function, scic; - u16 swsci_val; - u32 dslp; + struct opregion_swsci *swsci = i915->opregion.swsci; + u32 main_function, sub_function; if (!swsci) return -ENODEV; @@ -264,15 +261,31 @@ static int swsci(struct drm_i915_private *dev_priv, /* Check if we can call the function. See swsci_setup for details. */ if (main_function == SWSCI_SBCB) { - if ((dev_priv->opregion.swsci_sbcb_sub_functions & + if ((i915->opregion.swsci_sbcb_sub_functions & (1 << sub_function)) == 0) return -EINVAL; } else if (main_function == SWSCI_GBDA) { - if ((dev_priv->opregion.swsci_gbda_sub_functions & + if ((i915->opregion.swsci_gbda_sub_functions & (1 << sub_function)) == 0) return -EINVAL; } + return 0; +} + +static int swsci(struct drm_i915_private *dev_priv, + u32 function, u32 parm, u32 *parm_out) +{ + struct opregion_swsci *swsci = dev_priv->opregion.swsci; + struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); + u32 scic, dslp; + u16 swsci_val; + int ret; + + ret = check_swsci_function(dev_priv, function); + if (ret) + return ret; + /* Driver sleep timeout in ms. */ dslp = swsci->dslp; if (!dslp) { @@ -346,11 +359,17 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, u32 parm = 0; u32 type = 0; u32 port; + int ret; /* don't care about old stuff for now */ if (!HAS_DDI(dev_priv)) return 0; + /* Avoid port out of bounds checks if SWSCI isn't there. */ + ret = check_swsci_function(dev_priv, SWSCI_SBCB_DISPLAY_POWER_STATE); + if (ret) + return ret; + if (intel_encoder->type == INTEL_OUTPUT_DSI) port = 0; else @@ -363,6 +382,21 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, port++; } + /* + * The port numbering and mapping here is bizarre. The now-obsolete + * swsci spec supports ports numbered [0..4]. Port E is handled as a + * special case, but port F and beyond are not. The functionality is + * supposed to be obsolete for new platforms. Just bail out if the port + * number is out of bounds after mapping. + */ + if (port > 4) { + drm_dbg_kms(&dev_priv->drm, + "[ENCODER:%d:%s] port %c (index %u) out of bounds for display power state notification\n", + intel_encoder->base.base.id, intel_encoder->base.name, + port_name(intel_encoder->port), port); + return -EINVAL; + } + if (!enable) parm |= 4 << 8; @@ -899,9 +933,17 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) } if (mboxes & MBOX_SWSCI) { - drm_dbg(&dev_priv->drm, "SWSCI supported\n"); - opregion->swsci = base + OPREGION_SWSCI_OFFSET; - swsci_setup(dev_priv); + u8 major = opregion->header->over.major; + + if (major >= 3) { + drm_err(&dev_priv->drm, "SWSCI Mailbox #2 present for opregion v3.x, ignoring\n"); + } else { + if (major >= 2) + drm_dbg(&dev_priv->drm, "SWSCI Mailbox #2 present for opregion v2.x\n"); + drm_dbg(&dev_priv->drm, "SWSCI supported\n"); + opregion->swsci = base + OPREGION_SWSCI_OFFSET; + swsci_setup(dev_priv); + } } if (mboxes & MBOX_ASLE) { @@ -916,6 +958,10 @@ int intel_opregion_setup(struct drm_i915_private *dev_priv) opregion->asle_ext = base + OPREGION_ASLE_EXT_OFFSET; } + if (mboxes & MBOX_BACKLIGHT) { + drm_dbg(&dev_priv->drm, "Mailbox #2 for backlight present\n"); + } + if (intel_load_vbt_firmware(dev_priv) == 0) goto out; |