linux/drivers/gpu/drm/i915/intel_opregion.c
<<
>>
Prefs
   1/*
   2 * Copyright 2008 Intel Corporation <hong.liu@intel.com>
   3 * Copyright 2008 Red Hat <mjg@redhat.com>
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining
   6 * a copy of this software and associated documentation files (the
   7 * "Software"), to deal in the Software without restriction, including
   8 * without limitation the rights to use, copy, modify, merge, publish,
   9 * distribute, sub license, and/or sell copies of the Software, and to
  10 * permit persons to whom the Software is furnished to do so, subject to
  11 * the following conditions:
  12 *
  13 * The above copyright notice and this permission notice (including the
  14 * next paragraph) shall be included in all copies or substantial
  15 * portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20 * NON-INFRINGEMENT.  IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS BE
  21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24 * SOFTWARE.
  25 *
  26 */
  27
  28#include <linux/acpi.h>
  29#include <linux/dmi.h>
  30#include <linux/firmware.h>
  31#include <acpi/video.h>
  32
  33#include <drm/drmP.h>
  34#include <drm/i915_drm.h>
  35
  36#include "intel_opregion.h"
  37#include "i915_drv.h"
  38#include "intel_drv.h"
  39
  40#define OPREGION_HEADER_OFFSET 0
  41#define OPREGION_ACPI_OFFSET   0x100
  42#define   ACPI_CLID 0x01ac /* current lid state indicator */
  43#define   ACPI_CDCK 0x01b0 /* current docking state indicator */
  44#define OPREGION_SWSCI_OFFSET  0x200
  45#define OPREGION_ASLE_OFFSET   0x300
  46#define OPREGION_VBT_OFFSET    0x400
  47#define OPREGION_ASLE_EXT_OFFSET        0x1C00
  48
  49#define OPREGION_SIGNATURE "IntelGraphicsMem"
  50#define MBOX_ACPI      (1<<0)
  51#define MBOX_SWSCI     (1<<1)
  52#define MBOX_ASLE      (1<<2)
  53#define MBOX_ASLE_EXT  (1<<4)
  54
  55struct opregion_header {
  56        u8 signature[16];
  57        u32 size;
  58        u32 opregion_ver;
  59        u8 bios_ver[32];
  60        u8 vbios_ver[16];
  61        u8 driver_ver[16];
  62        u32 mboxes;
  63        u32 driver_model;
  64        u32 pcon;
  65        u8 dver[32];
  66        u8 rsvd[124];
  67} __packed;
  68
  69/* OpRegion mailbox #1: public ACPI methods */
  70struct opregion_acpi {
  71        u32 drdy;       /* driver readiness */
  72        u32 csts;       /* notification status */
  73        u32 cevt;       /* current event */
  74        u8 rsvd1[20];
  75        u32 didl[8];    /* supported display devices ID list */
  76        u32 cpdl[8];    /* currently presented display list */
  77        u32 cadl[8];    /* currently active display list */
  78        u32 nadl[8];    /* next active devices list */
  79        u32 aslp;       /* ASL sleep time-out */
  80        u32 tidx;       /* toggle table index */
  81        u32 chpd;       /* current hotplug enable indicator */
  82        u32 clid;       /* current lid state*/
  83        u32 cdck;       /* current docking state */
  84        u32 sxsw;       /* Sx state resume */
  85        u32 evts;       /* ASL supported events */
  86        u32 cnot;       /* current OS notification */
  87        u32 nrdy;       /* driver status */
  88        u32 did2[7];    /* extended supported display devices ID list */
  89        u32 cpd2[7];    /* extended attached display devices list */
  90        u8 rsvd2[4];
  91} __packed;
  92
  93/* OpRegion mailbox #2: SWSCI */
  94struct opregion_swsci {
  95        u32 scic;       /* SWSCI command|status|data */
  96        u32 parm;       /* command parameters */
  97        u32 dslp;       /* driver sleep time-out */
  98        u8 rsvd[244];
  99} __packed;
 100
 101/* OpRegion mailbox #3: ASLE */
 102struct opregion_asle {
 103        u32 ardy;       /* driver readiness */
 104        u32 aslc;       /* ASLE interrupt command */
 105        u32 tche;       /* technology enabled indicator */
 106        u32 alsi;       /* current ALS illuminance reading */
 107        u32 bclp;       /* backlight brightness to set */
 108        u32 pfit;       /* panel fitting state */
 109        u32 cblv;       /* current brightness level */
 110        u16 bclm[20];   /* backlight level duty cycle mapping table */
 111        u32 cpfm;       /* current panel fitting mode */
 112        u32 epfm;       /* enabled panel fitting modes */
 113        u8 plut[74];    /* panel LUT and identifier */
 114        u32 pfmb;       /* PWM freq and min brightness */
 115        u32 cddv;       /* color correction default values */
 116        u32 pcft;       /* power conservation features */
 117        u32 srot;       /* supported rotation angles */
 118        u32 iuer;       /* IUER events */
 119        u64 fdss;
 120        u32 fdsp;
 121        u32 stat;
 122        u64 rvda;       /* Physical address of raw vbt data */
 123        u32 rvds;       /* Size of raw vbt data */
 124        u8 rsvd[58];
 125} __packed;
 126
 127/* OpRegion mailbox #5: ASLE ext */
 128struct opregion_asle_ext {
 129        u32 phed;       /* Panel Header */
 130        u8 bddc[256];   /* Panel EDID */
 131        u8 rsvd[764];
 132} __packed;
 133
 134/* Driver readiness indicator */
 135#define ASLE_ARDY_READY         (1 << 0)
 136#define ASLE_ARDY_NOT_READY     (0 << 0)
 137
 138/* ASLE Interrupt Command (ASLC) bits */
 139#define ASLC_SET_ALS_ILLUM              (1 << 0)
 140#define ASLC_SET_BACKLIGHT              (1 << 1)
 141#define ASLC_SET_PFIT                   (1 << 2)
 142#define ASLC_SET_PWM_FREQ               (1 << 3)
 143#define ASLC_SUPPORTED_ROTATION_ANGLES  (1 << 4)
 144#define ASLC_BUTTON_ARRAY               (1 << 5)
 145#define ASLC_CONVERTIBLE_INDICATOR      (1 << 6)
 146#define ASLC_DOCKING_INDICATOR          (1 << 7)
 147#define ASLC_ISCT_STATE_CHANGE          (1 << 8)
 148#define ASLC_REQ_MSK                    0x1ff
 149/* response bits */
 150#define ASLC_ALS_ILLUM_FAILED           (1 << 10)
 151#define ASLC_BACKLIGHT_FAILED           (1 << 12)
 152#define ASLC_PFIT_FAILED                (1 << 14)
 153#define ASLC_PWM_FREQ_FAILED            (1 << 16)
 154#define ASLC_ROTATION_ANGLES_FAILED     (1 << 18)
 155#define ASLC_BUTTON_ARRAY_FAILED        (1 << 20)
 156#define ASLC_CONVERTIBLE_FAILED         (1 << 22)
 157#define ASLC_DOCKING_FAILED             (1 << 24)
 158#define ASLC_ISCT_STATE_FAILED          (1 << 26)
 159
 160/* Technology enabled indicator */
 161#define ASLE_TCHE_ALS_EN        (1 << 0)
 162#define ASLE_TCHE_BLC_EN        (1 << 1)
 163#define ASLE_TCHE_PFIT_EN       (1 << 2)
 164#define ASLE_TCHE_PFMB_EN       (1 << 3)
 165
 166/* ASLE backlight brightness to set */
 167#define ASLE_BCLP_VALID                (1<<31)
 168#define ASLE_BCLP_MSK          (~(1<<31))
 169
 170/* ASLE panel fitting request */
 171#define ASLE_PFIT_VALID         (1<<31)
 172#define ASLE_PFIT_CENTER (1<<0)
 173#define ASLE_PFIT_STRETCH_TEXT (1<<1)
 174#define ASLE_PFIT_STRETCH_GFX (1<<2)
 175
 176/* PWM frequency and minimum brightness */
 177#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
 178#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
 179#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
 180#define ASLE_PFMB_PWM_VALID (1<<31)
 181
 182#define ASLE_CBLV_VALID         (1<<31)
 183
 184/* IUER */
 185#define ASLE_IUER_DOCKING               (1 << 7)
 186#define ASLE_IUER_CONVERTIBLE           (1 << 6)
 187#define ASLE_IUER_ROTATION_LOCK_BTN     (1 << 4)
 188#define ASLE_IUER_VOLUME_DOWN_BTN       (1 << 3)
 189#define ASLE_IUER_VOLUME_UP_BTN         (1 << 2)
 190#define ASLE_IUER_WINDOWS_BTN           (1 << 1)
 191#define ASLE_IUER_POWER_BTN             (1 << 0)
 192
 193/* Software System Control Interrupt (SWSCI) */
 194#define SWSCI_SCIC_INDICATOR            (1 << 0)
 195#define SWSCI_SCIC_MAIN_FUNCTION_SHIFT  1
 196#define SWSCI_SCIC_MAIN_FUNCTION_MASK   (0xf << 1)
 197#define SWSCI_SCIC_SUB_FUNCTION_SHIFT   8
 198#define SWSCI_SCIC_SUB_FUNCTION_MASK    (0xff << 8)
 199#define SWSCI_SCIC_EXIT_PARAMETER_SHIFT 8
 200#define SWSCI_SCIC_EXIT_PARAMETER_MASK  (0xff << 8)
 201#define SWSCI_SCIC_EXIT_STATUS_SHIFT    5
 202#define SWSCI_SCIC_EXIT_STATUS_MASK     (7 << 5)
 203#define SWSCI_SCIC_EXIT_STATUS_SUCCESS  1
 204
 205#define SWSCI_FUNCTION_CODE(main, sub) \
 206        ((main) << SWSCI_SCIC_MAIN_FUNCTION_SHIFT | \
 207         (sub) << SWSCI_SCIC_SUB_FUNCTION_SHIFT)
 208
 209/* SWSCI: Get BIOS Data (GBDA) */
 210#define SWSCI_GBDA                      4
 211#define SWSCI_GBDA_SUPPORTED_CALLS      SWSCI_FUNCTION_CODE(SWSCI_GBDA, 0)
 212#define SWSCI_GBDA_REQUESTED_CALLBACKS  SWSCI_FUNCTION_CODE(SWSCI_GBDA, 1)
 213#define SWSCI_GBDA_BOOT_DISPLAY_PREF    SWSCI_FUNCTION_CODE(SWSCI_GBDA, 4)
 214#define SWSCI_GBDA_PANEL_DETAILS        SWSCI_FUNCTION_CODE(SWSCI_GBDA, 5)
 215#define SWSCI_GBDA_TV_STANDARD          SWSCI_FUNCTION_CODE(SWSCI_GBDA, 6)
 216#define SWSCI_GBDA_INTERNAL_GRAPHICS    SWSCI_FUNCTION_CODE(SWSCI_GBDA, 7)
 217#define SWSCI_GBDA_SPREAD_SPECTRUM      SWSCI_FUNCTION_CODE(SWSCI_GBDA, 10)
 218
 219/* SWSCI: System BIOS Callbacks (SBCB) */
 220#define SWSCI_SBCB                      6
 221#define SWSCI_SBCB_SUPPORTED_CALLBACKS  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 0)
 222#define SWSCI_SBCB_INIT_COMPLETION      SWSCI_FUNCTION_CODE(SWSCI_SBCB, 1)
 223#define SWSCI_SBCB_PRE_HIRES_SET_MODE   SWSCI_FUNCTION_CODE(SWSCI_SBCB, 3)
 224#define SWSCI_SBCB_POST_HIRES_SET_MODE  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 4)
 225#define SWSCI_SBCB_DISPLAY_SWITCH       SWSCI_FUNCTION_CODE(SWSCI_SBCB, 5)
 226#define SWSCI_SBCB_SET_TV_FORMAT        SWSCI_FUNCTION_CODE(SWSCI_SBCB, 6)
 227#define SWSCI_SBCB_ADAPTER_POWER_STATE  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 7)
 228#define SWSCI_SBCB_DISPLAY_POWER_STATE  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 8)
 229#define SWSCI_SBCB_SET_BOOT_DISPLAY     SWSCI_FUNCTION_CODE(SWSCI_SBCB, 9)
 230#define SWSCI_SBCB_SET_PANEL_DETAILS    SWSCI_FUNCTION_CODE(SWSCI_SBCB, 10)
 231#define SWSCI_SBCB_SET_INTERNAL_GFX     SWSCI_FUNCTION_CODE(SWSCI_SBCB, 11)
 232#define SWSCI_SBCB_POST_HIRES_TO_DOS_FS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 16)
 233#define SWSCI_SBCB_SUSPEND_RESUME       SWSCI_FUNCTION_CODE(SWSCI_SBCB, 17)
 234#define SWSCI_SBCB_SET_SPREAD_SPECTRUM  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 18)
 235#define SWSCI_SBCB_POST_VBE_PM          SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19)
 236#define SWSCI_SBCB_ENABLE_DISABLE_AUDIO SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21)
 237
 238/*
 239 * ACPI Specification, Revision 5.0, Appendix B.3.2 _DOD (Enumerate All Devices
 240 * Attached to the Display Adapter).
 241 */
 242#define ACPI_DISPLAY_INDEX_SHIFT                0
 243#define ACPI_DISPLAY_INDEX_MASK                 (0xf << 0)
 244#define ACPI_DISPLAY_PORT_ATTACHMENT_SHIFT      4
 245#define ACPI_DISPLAY_PORT_ATTACHMENT_MASK       (0xf << 4)
 246#define ACPI_DISPLAY_TYPE_SHIFT                 8
 247#define ACPI_DISPLAY_TYPE_MASK                  (0xf << 8)
 248#define ACPI_DISPLAY_TYPE_OTHER                 (0 << 8)
 249#define ACPI_DISPLAY_TYPE_VGA                   (1 << 8)
 250#define ACPI_DISPLAY_TYPE_TV                    (2 << 8)
 251#define ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL      (3 << 8)
 252#define ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL      (4 << 8)
 253#define ACPI_VENDOR_SPECIFIC_SHIFT              12
 254#define ACPI_VENDOR_SPECIFIC_MASK               (0xf << 12)
 255#define ACPI_BIOS_CAN_DETECT                    (1 << 16)
 256#define ACPI_DEPENDS_ON_VGA                     (1 << 17)
 257#define ACPI_PIPE_ID_SHIFT                      18
 258#define ACPI_PIPE_ID_MASK                       (7 << 18)
 259#define ACPI_DEVICE_ID_SCHEME                   (1 << 31)
 260
 261#define MAX_DSLP        1500
 262
 263static int swsci(struct drm_i915_private *dev_priv,
 264                 u32 function, u32 parm, u32 *parm_out)
 265{
 266        struct opregion_swsci *swsci = dev_priv->opregion.swsci;
 267        struct pci_dev *pdev = dev_priv->drm.pdev;
 268        u32 main_function, sub_function, scic;
 269        u16 swsci_val;
 270        u32 dslp;
 271
 272        if (!swsci)
 273                return -ENODEV;
 274
 275        main_function = (function & SWSCI_SCIC_MAIN_FUNCTION_MASK) >>
 276                SWSCI_SCIC_MAIN_FUNCTION_SHIFT;
 277        sub_function = (function & SWSCI_SCIC_SUB_FUNCTION_MASK) >>
 278                SWSCI_SCIC_SUB_FUNCTION_SHIFT;
 279
 280        /* Check if we can call the function. See swsci_setup for details. */
 281        if (main_function == SWSCI_SBCB) {
 282                if ((dev_priv->opregion.swsci_sbcb_sub_functions &
 283                     (1 << sub_function)) == 0)
 284                        return -EINVAL;
 285        } else if (main_function == SWSCI_GBDA) {
 286                if ((dev_priv->opregion.swsci_gbda_sub_functions &
 287                     (1 << sub_function)) == 0)
 288                        return -EINVAL;
 289        }
 290
 291        /* Driver sleep timeout in ms. */
 292        dslp = swsci->dslp;
 293        if (!dslp) {
 294                /* The spec says 2ms should be the default, but it's too small
 295                 * for some machines. */
 296                dslp = 50;
 297        } else if (dslp > MAX_DSLP) {
 298                /* Hey bios, trust must be earned. */
 299                DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, "
 300                              "using %u ms instead\n", dslp, MAX_DSLP);
 301                dslp = MAX_DSLP;
 302        }
 303
 304        /* The spec tells us to do this, but we are the only user... */
 305        scic = swsci->scic;
 306        if (scic & SWSCI_SCIC_INDICATOR) {
 307                DRM_DEBUG_DRIVER("SWSCI request already in progress\n");
 308                return -EBUSY;
 309        }
 310
 311        scic = function | SWSCI_SCIC_INDICATOR;
 312
 313        swsci->parm = parm;
 314        swsci->scic = scic;
 315
 316        /* Ensure SCI event is selected and event trigger is cleared. */
 317        pci_read_config_word(pdev, SWSCI, &swsci_val);
 318        if (!(swsci_val & SWSCI_SCISEL) || (swsci_val & SWSCI_GSSCIE)) {
 319                swsci_val |= SWSCI_SCISEL;
 320                swsci_val &= ~SWSCI_GSSCIE;
 321                pci_write_config_word(pdev, SWSCI, swsci_val);
 322        }
 323
 324        /* Use event trigger to tell bios to check the mail. */
 325        swsci_val |= SWSCI_GSSCIE;
 326        pci_write_config_word(pdev, SWSCI, swsci_val);
 327
 328        /* Poll for the result. */
 329#define C (((scic = swsci->scic) & SWSCI_SCIC_INDICATOR) == 0)
 330        if (wait_for(C, dslp)) {
 331                DRM_DEBUG_DRIVER("SWSCI request timed out\n");
 332                return -ETIMEDOUT;
 333        }
 334
 335        scic = (scic & SWSCI_SCIC_EXIT_STATUS_MASK) >>
 336                SWSCI_SCIC_EXIT_STATUS_SHIFT;
 337
 338        /* Note: scic == 0 is an error! */
 339        if (scic != SWSCI_SCIC_EXIT_STATUS_SUCCESS) {
 340                DRM_DEBUG_DRIVER("SWSCI request error %u\n", scic);
 341                return -EIO;
 342        }
 343
 344        if (parm_out)
 345                *parm_out = swsci->parm;
 346
 347        return 0;
 348
 349#undef C
 350}
 351
 352#define DISPLAY_TYPE_CRT                        0
 353#define DISPLAY_TYPE_TV                         1
 354#define DISPLAY_TYPE_EXTERNAL_FLAT_PANEL        2
 355#define DISPLAY_TYPE_INTERNAL_FLAT_PANEL        3
 356
 357int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
 358                                  bool enable)
 359{
 360        struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
 361        u32 parm = 0;
 362        u32 type = 0;
 363        u32 port;
 364
 365        /* don't care about old stuff for now */
 366        if (!HAS_DDI(dev_priv))
 367                return 0;
 368
 369        if (intel_encoder->type == INTEL_OUTPUT_DSI)
 370                port = 0;
 371        else
 372                port = intel_encoder->port;
 373
 374        if (port == PORT_E)  {
 375                port = 0;
 376        } else {
 377                parm |= 1 << port;
 378                port++;
 379        }
 380
 381        if (!enable)
 382                parm |= 4 << 8;
 383
 384        switch (intel_encoder->type) {
 385        case INTEL_OUTPUT_ANALOG:
 386                type = DISPLAY_TYPE_CRT;
 387                break;
 388        case INTEL_OUTPUT_DDI:
 389        case INTEL_OUTPUT_DP:
 390        case INTEL_OUTPUT_HDMI:
 391        case INTEL_OUTPUT_DP_MST:
 392                type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL;
 393                break;
 394        case INTEL_OUTPUT_EDP:
 395        case INTEL_OUTPUT_DSI:
 396                type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL;
 397                break;
 398        default:
 399                WARN_ONCE(1, "unsupported intel_encoder type %d\n",
 400                          intel_encoder->type);
 401                return -EINVAL;
 402        }
 403
 404        parm |= type << (16 + port * 3);
 405
 406        return swsci(dev_priv, SWSCI_SBCB_DISPLAY_POWER_STATE, parm, NULL);
 407}
 408
 409static const struct {
 410        pci_power_t pci_power_state;
 411        u32 parm;
 412} power_state_map[] = {
 413        { PCI_D0,       0x00 },
 414        { PCI_D1,       0x01 },
 415        { PCI_D2,       0x02 },
 416        { PCI_D3hot,    0x04 },
 417        { PCI_D3cold,   0x04 },
 418};
 419
 420int intel_opregion_notify_adapter(struct drm_i915_private *dev_priv,
 421                                  pci_power_t state)
 422{
 423        int i;
 424
 425        if (!HAS_DDI(dev_priv))
 426                return 0;
 427
 428        for (i = 0; i < ARRAY_SIZE(power_state_map); i++) {
 429                if (state == power_state_map[i].pci_power_state)
 430                        return swsci(dev_priv, SWSCI_SBCB_ADAPTER_POWER_STATE,
 431                                     power_state_map[i].parm, NULL);
 432        }
 433
 434        return -EINVAL;
 435}
 436
 437static u32 asle_set_backlight(struct drm_i915_private *dev_priv, u32 bclp)
 438{
 439        struct intel_connector *connector;
 440        struct drm_connector_list_iter conn_iter;
 441        struct opregion_asle *asle = dev_priv->opregion.asle;
 442        struct drm_device *dev = &dev_priv->drm;
 443
 444        DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
 445
 446        if (acpi_video_get_backlight_type() == acpi_backlight_native) {
 447                DRM_DEBUG_KMS("opregion backlight request ignored\n");
 448                return 0;
 449        }
 450
 451        if (!(bclp & ASLE_BCLP_VALID))
 452                return ASLC_BACKLIGHT_FAILED;
 453
 454        bclp &= ASLE_BCLP_MSK;
 455        if (bclp > 255)
 456                return ASLC_BACKLIGHT_FAILED;
 457
 458        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 459
 460        /*
 461         * Update backlight on all connectors that support backlight (usually
 462         * only one).
 463         */
 464        DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp);
 465        drm_connector_list_iter_begin(dev, &conn_iter);
 466        for_each_intel_connector_iter(connector, &conn_iter)
 467                intel_panel_set_backlight_acpi(connector->base.state, bclp, 255);
 468        drm_connector_list_iter_end(&conn_iter);
 469        asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID;
 470
 471        drm_modeset_unlock(&dev->mode_config.connection_mutex);
 472
 473
 474        return 0;
 475}
 476
 477static u32 asle_set_als_illum(struct drm_i915_private *dev_priv, u32 alsi)
 478{
 479        /* alsi is the current ALS reading in lux. 0 indicates below sensor
 480           range, 0xffff indicates above sensor range. 1-0xfffe are valid */
 481        DRM_DEBUG_DRIVER("Illum is not supported\n");
 482        return ASLC_ALS_ILLUM_FAILED;
 483}
 484
 485static u32 asle_set_pwm_freq(struct drm_i915_private *dev_priv, u32 pfmb)
 486{
 487        DRM_DEBUG_DRIVER("PWM freq is not supported\n");
 488        return ASLC_PWM_FREQ_FAILED;
 489}
 490
 491static u32 asle_set_pfit(struct drm_i915_private *dev_priv, u32 pfit)
 492{
 493        /* Panel fitting is currently controlled by the X code, so this is a
 494           noop until modesetting support works fully */
 495        DRM_DEBUG_DRIVER("Pfit is not supported\n");
 496        return ASLC_PFIT_FAILED;
 497}
 498
 499static u32 asle_set_supported_rotation_angles(struct drm_i915_private *dev_priv, u32 srot)
 500{
 501        DRM_DEBUG_DRIVER("SROT is not supported\n");
 502        return ASLC_ROTATION_ANGLES_FAILED;
 503}
 504
 505static u32 asle_set_button_array(struct drm_i915_private *dev_priv, u32 iuer)
 506{
 507        if (!iuer)
 508                DRM_DEBUG_DRIVER("Button array event is not supported (nothing)\n");
 509        if (iuer & ASLE_IUER_ROTATION_LOCK_BTN)
 510                DRM_DEBUG_DRIVER("Button array event is not supported (rotation lock)\n");
 511        if (iuer & ASLE_IUER_VOLUME_DOWN_BTN)
 512                DRM_DEBUG_DRIVER("Button array event is not supported (volume down)\n");
 513        if (iuer & ASLE_IUER_VOLUME_UP_BTN)
 514                DRM_DEBUG_DRIVER("Button array event is not supported (volume up)\n");
 515        if (iuer & ASLE_IUER_WINDOWS_BTN)
 516                DRM_DEBUG_DRIVER("Button array event is not supported (windows)\n");
 517        if (iuer & ASLE_IUER_POWER_BTN)
 518                DRM_DEBUG_DRIVER("Button array event is not supported (power)\n");
 519
 520        return ASLC_BUTTON_ARRAY_FAILED;
 521}
 522
 523static u32 asle_set_convertible(struct drm_i915_private *dev_priv, u32 iuer)
 524{
 525        if (iuer & ASLE_IUER_CONVERTIBLE)
 526                DRM_DEBUG_DRIVER("Convertible is not supported (clamshell)\n");
 527        else
 528                DRM_DEBUG_DRIVER("Convertible is not supported (slate)\n");
 529
 530        return ASLC_CONVERTIBLE_FAILED;
 531}
 532
 533static u32 asle_set_docking(struct drm_i915_private *dev_priv, u32 iuer)
 534{
 535        if (iuer & ASLE_IUER_DOCKING)
 536                DRM_DEBUG_DRIVER("Docking is not supported (docked)\n");
 537        else
 538                DRM_DEBUG_DRIVER("Docking is not supported (undocked)\n");
 539
 540        return ASLC_DOCKING_FAILED;
 541}
 542
 543static u32 asle_isct_state(struct drm_i915_private *dev_priv)
 544{
 545        DRM_DEBUG_DRIVER("ISCT is not supported\n");
 546        return ASLC_ISCT_STATE_FAILED;
 547}
 548
 549static void asle_work(struct work_struct *work)
 550{
 551        struct intel_opregion *opregion =
 552                container_of(work, struct intel_opregion, asle_work);
 553        struct drm_i915_private *dev_priv =
 554                container_of(opregion, struct drm_i915_private, opregion);
 555        struct opregion_asle *asle = dev_priv->opregion.asle;
 556        u32 aslc_stat = 0;
 557        u32 aslc_req;
 558
 559        if (!asle)
 560                return;
 561
 562        aslc_req = asle->aslc;
 563
 564        if (!(aslc_req & ASLC_REQ_MSK)) {
 565                DRM_DEBUG_DRIVER("No request on ASLC interrupt 0x%08x\n",
 566                                 aslc_req);
 567                return;
 568        }
 569
 570        if (aslc_req & ASLC_SET_ALS_ILLUM)
 571                aslc_stat |= asle_set_als_illum(dev_priv, asle->alsi);
 572
 573        if (aslc_req & ASLC_SET_BACKLIGHT)
 574                aslc_stat |= asle_set_backlight(dev_priv, asle->bclp);
 575
 576        if (aslc_req & ASLC_SET_PFIT)
 577                aslc_stat |= asle_set_pfit(dev_priv, asle->pfit);
 578
 579        if (aslc_req & ASLC_SET_PWM_FREQ)
 580                aslc_stat |= asle_set_pwm_freq(dev_priv, asle->pfmb);
 581
 582        if (aslc_req & ASLC_SUPPORTED_ROTATION_ANGLES)
 583                aslc_stat |= asle_set_supported_rotation_angles(dev_priv,
 584                                                        asle->srot);
 585
 586        if (aslc_req & ASLC_BUTTON_ARRAY)
 587                aslc_stat |= asle_set_button_array(dev_priv, asle->iuer);
 588
 589        if (aslc_req & ASLC_CONVERTIBLE_INDICATOR)
 590                aslc_stat |= asle_set_convertible(dev_priv, asle->iuer);
 591
 592        if (aslc_req & ASLC_DOCKING_INDICATOR)
 593                aslc_stat |= asle_set_docking(dev_priv, asle->iuer);
 594
 595        if (aslc_req & ASLC_ISCT_STATE_CHANGE)
 596                aslc_stat |= asle_isct_state(dev_priv);
 597
 598        asle->aslc = aslc_stat;
 599}
 600
 601void intel_opregion_asle_intr(struct drm_i915_private *dev_priv)
 602{
 603        if (dev_priv->opregion.asle)
 604                schedule_work(&dev_priv->opregion.asle_work);
 605}
 606
 607#define ACPI_EV_DISPLAY_SWITCH (1<<0)
 608#define ACPI_EV_LID            (1<<1)
 609#define ACPI_EV_DOCK           (1<<2)
 610
 611static struct intel_opregion *system_opregion;
 612
 613static int intel_opregion_video_event(struct notifier_block *nb,
 614                                      unsigned long val, void *data)
 615{
 616        /* The only video events relevant to opregion are 0x80. These indicate
 617           either a docking event, lid switch or display switch request. In
 618           Linux, these are handled by the dock, button and video drivers.
 619        */
 620
 621        struct acpi_bus_event *event = data;
 622        struct opregion_acpi *acpi;
 623        int ret = NOTIFY_OK;
 624
 625        if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
 626                return NOTIFY_DONE;
 627
 628        if (!system_opregion)
 629                return NOTIFY_DONE;
 630
 631        acpi = system_opregion->acpi;
 632
 633        if (event->type == 0x80 && ((acpi->cevt & 1) == 0))
 634                ret = NOTIFY_BAD;
 635
 636        acpi->csts = 0;
 637
 638        return ret;
 639}
 640
 641static struct notifier_block intel_opregion_notifier = {
 642        .notifier_call = intel_opregion_video_event,
 643};
 644
 645/*
 646 * Initialise the DIDL field in opregion. This passes a list of devices to
 647 * the firmware. Values are defined by section B.4.2 of the ACPI specification
 648 * (version 3)
 649 */
 650
 651static void set_did(struct intel_opregion *opregion, int i, u32 val)
 652{
 653        if (i < ARRAY_SIZE(opregion->acpi->didl)) {
 654                opregion->acpi->didl[i] = val;
 655        } else {
 656                i -= ARRAY_SIZE(opregion->acpi->didl);
 657
 658                if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2)))
 659                        return;
 660
 661                opregion->acpi->did2[i] = val;
 662        }
 663}
 664
 665static u32 acpi_display_type(struct intel_connector *connector)
 666{
 667        u32 display_type;
 668
 669        switch (connector->base.connector_type) {
 670        case DRM_MODE_CONNECTOR_VGA:
 671        case DRM_MODE_CONNECTOR_DVIA:
 672                display_type = ACPI_DISPLAY_TYPE_VGA;
 673                break;
 674        case DRM_MODE_CONNECTOR_Composite:
 675        case DRM_MODE_CONNECTOR_SVIDEO:
 676        case DRM_MODE_CONNECTOR_Component:
 677        case DRM_MODE_CONNECTOR_9PinDIN:
 678        case DRM_MODE_CONNECTOR_TV:
 679                display_type = ACPI_DISPLAY_TYPE_TV;
 680                break;
 681        case DRM_MODE_CONNECTOR_DVII:
 682        case DRM_MODE_CONNECTOR_DVID:
 683        case DRM_MODE_CONNECTOR_DisplayPort:
 684        case DRM_MODE_CONNECTOR_HDMIA:
 685        case DRM_MODE_CONNECTOR_HDMIB:
 686                display_type = ACPI_DISPLAY_TYPE_EXTERNAL_DIGITAL;
 687                break;
 688        case DRM_MODE_CONNECTOR_LVDS:
 689        case DRM_MODE_CONNECTOR_eDP:
 690        case DRM_MODE_CONNECTOR_DSI:
 691                display_type = ACPI_DISPLAY_TYPE_INTERNAL_DIGITAL;
 692                break;
 693        case DRM_MODE_CONNECTOR_Unknown:
 694        case DRM_MODE_CONNECTOR_VIRTUAL:
 695                display_type = ACPI_DISPLAY_TYPE_OTHER;
 696                break;
 697        default:
 698                MISSING_CASE(connector->base.connector_type);
 699                display_type = ACPI_DISPLAY_TYPE_OTHER;
 700                break;
 701        }
 702
 703        return display_type;
 704}
 705
 706static void intel_didl_outputs(struct drm_i915_private *dev_priv)
 707{
 708        struct intel_opregion *opregion = &dev_priv->opregion;
 709        struct intel_connector *connector;
 710        struct drm_connector_list_iter conn_iter;
 711        int i = 0, max_outputs;
 712        int display_index[16] = {};
 713
 714        /*
 715         * In theory, did2, the extended didl, gets added at opregion version
 716         * 3.0. In practice, however, we're supposed to set it for earlier
 717         * versions as well, since a BIOS that doesn't understand did2 should
 718         * not look at it anyway. Use a variable so we can tweak this if a need
 719         * arises later.
 720         */
 721        max_outputs = ARRAY_SIZE(opregion->acpi->didl) +
 722                ARRAY_SIZE(opregion->acpi->did2);
 723
 724        drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
 725        for_each_intel_connector_iter(connector, &conn_iter) {
 726                u32 device_id, type;
 727
 728                device_id = acpi_display_type(connector);
 729
 730                /* Use display type specific display index. */
 731                type = (device_id & ACPI_DISPLAY_TYPE_MASK)
 732                        >> ACPI_DISPLAY_TYPE_SHIFT;
 733                device_id |= display_index[type]++ << ACPI_DISPLAY_INDEX_SHIFT;
 734
 735                connector->acpi_device_id = device_id;
 736                if (i < max_outputs)
 737                        set_did(opregion, i, device_id);
 738                i++;
 739        }
 740        drm_connector_list_iter_end(&conn_iter);
 741
 742        DRM_DEBUG_KMS("%d outputs detected\n", i);
 743
 744        if (i > max_outputs)
 745                DRM_ERROR("More than %d outputs in connector list\n",
 746                          max_outputs);
 747
 748        /* If fewer than max outputs, the list must be null terminated */
 749        if (i < max_outputs)
 750                set_did(opregion, i, 0);
 751}
 752
 753static void intel_setup_cadls(struct drm_i915_private *dev_priv)
 754{
 755        struct intel_opregion *opregion = &dev_priv->opregion;
 756        struct intel_connector *connector;
 757        struct drm_connector_list_iter conn_iter;
 758        int i = 0;
 759
 760        /*
 761         * Initialize the CADL field from the connector device ids. This is
 762         * essentially the same as copying from the DIDL. Technically, this is
 763         * not always correct as display outputs may exist, but not active. This
 764         * initialization is necessary for some Clevo laptops that check this
 765         * field before processing the brightness and display switching hotkeys.
 766         *
 767         * Note that internal panels should be at the front of the connector
 768         * list already, ensuring they're not left out.
 769         */
 770        drm_connector_list_iter_begin(&dev_priv->drm, &conn_iter);
 771        for_each_intel_connector_iter(connector, &conn_iter) {
 772                if (i >= ARRAY_SIZE(opregion->acpi->cadl))
 773                        break;
 774                opregion->acpi->cadl[i++] = connector->acpi_device_id;
 775        }
 776        drm_connector_list_iter_end(&conn_iter);
 777
 778        /* If fewer than 8 active devices, the list must be null terminated */
 779        if (i < ARRAY_SIZE(opregion->acpi->cadl))
 780                opregion->acpi->cadl[i] = 0;
 781}
 782
 783void intel_opregion_register(struct drm_i915_private *dev_priv)
 784{
 785        struct intel_opregion *opregion = &dev_priv->opregion;
 786
 787        if (!opregion->header)
 788                return;
 789
 790        if (opregion->acpi) {
 791                intel_didl_outputs(dev_priv);
 792                intel_setup_cadls(dev_priv);
 793
 794                /* Notify BIOS we are ready to handle ACPI video ext notifs.
 795                 * Right now, all the events are handled by the ACPI video module.
 796                 * We don't actually need to do anything with them. */
 797                opregion->acpi->csts = 0;
 798                opregion->acpi->drdy = 1;
 799
 800                system_opregion = opregion;
 801                register_acpi_notifier(&intel_opregion_notifier);
 802        }
 803
 804        if (opregion->asle) {
 805                opregion->asle->tche = ASLE_TCHE_BLC_EN;
 806                opregion->asle->ardy = ASLE_ARDY_READY;
 807        }
 808}
 809
 810void intel_opregion_unregister(struct drm_i915_private *dev_priv)
 811{
 812        struct intel_opregion *opregion = &dev_priv->opregion;
 813
 814        if (!opregion->header)
 815                return;
 816
 817        if (opregion->asle)
 818                opregion->asle->ardy = ASLE_ARDY_NOT_READY;
 819
 820        cancel_work_sync(&dev_priv->opregion.asle_work);
 821
 822        if (opregion->acpi) {
 823                opregion->acpi->drdy = 0;
 824
 825                system_opregion = NULL;
 826                unregister_acpi_notifier(&intel_opregion_notifier);
 827        }
 828
 829        /* just clear all opregion memory pointers now */
 830        memunmap(opregion->header);
 831        if (opregion->rvda) {
 832                memunmap(opregion->rvda);
 833                opregion->rvda = NULL;
 834        }
 835        if (opregion->vbt_firmware) {
 836                kfree(opregion->vbt_firmware);
 837                opregion->vbt_firmware = NULL;
 838        }
 839        opregion->header = NULL;
 840        opregion->acpi = NULL;
 841        opregion->swsci = NULL;
 842        opregion->asle = NULL;
 843        opregion->vbt = NULL;
 844        opregion->lid_state = NULL;
 845}
 846
 847static void swsci_setup(struct drm_i915_private *dev_priv)
 848{
 849        struct intel_opregion *opregion = &dev_priv->opregion;
 850        bool requested_callbacks = false;
 851        u32 tmp;
 852
 853        /* Sub-function code 0 is okay, let's allow them. */
 854        opregion->swsci_gbda_sub_functions = 1;
 855        opregion->swsci_sbcb_sub_functions = 1;
 856
 857        /* We use GBDA to ask for supported GBDA calls. */
 858        if (swsci(dev_priv, SWSCI_GBDA_SUPPORTED_CALLS, 0, &tmp) == 0) {
 859                /* make the bits match the sub-function codes */
 860                tmp <<= 1;
 861                opregion->swsci_gbda_sub_functions |= tmp;
 862        }
 863
 864        /*
 865         * We also use GBDA to ask for _requested_ SBCB callbacks. The driver
 866         * must not call interfaces that are not specifically requested by the
 867         * bios.
 868         */
 869        if (swsci(dev_priv, SWSCI_GBDA_REQUESTED_CALLBACKS, 0, &tmp) == 0) {
 870                /* here, the bits already match sub-function codes */
 871                opregion->swsci_sbcb_sub_functions |= tmp;
 872                requested_callbacks = true;
 873        }
 874
 875        /*
 876         * But we use SBCB to ask for _supported_ SBCB calls. This does not mean
 877         * the callback is _requested_. But we still can't call interfaces that
 878         * are not requested.
 879         */
 880        if (swsci(dev_priv, SWSCI_SBCB_SUPPORTED_CALLBACKS, 0, &tmp) == 0) {
 881                /* make the bits match the sub-function codes */
 882                u32 low = tmp & 0x7ff;
 883                u32 high = tmp & ~0xfff; /* bit 11 is reserved */
 884                tmp = (high << 4) | (low << 1) | 1;
 885
 886                /* best guess what to do with supported wrt requested */
 887                if (requested_callbacks) {
 888                        u32 req = opregion->swsci_sbcb_sub_functions;
 889                        if ((req & tmp) != req)
 890                                DRM_DEBUG_DRIVER("SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n", req, tmp);
 891                        /* XXX: for now, trust the requested callbacks */
 892                        /* opregion->swsci_sbcb_sub_functions &= tmp; */
 893                } else {
 894                        opregion->swsci_sbcb_sub_functions |= tmp;
 895                }
 896        }
 897
 898        DRM_DEBUG_DRIVER("SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n",
 899                         opregion->swsci_gbda_sub_functions,
 900                         opregion->swsci_sbcb_sub_functions);
 901}
 902
 903static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
 904{
 905        DRM_DEBUG_KMS("Falling back to manually reading VBT from "
 906                      "VBIOS ROM for %s\n", id->ident);
 907        return 1;
 908}
 909
 910static const struct dmi_system_id intel_no_opregion_vbt[] = {
 911        {
 912                .callback = intel_no_opregion_vbt_callback,
 913                .ident = "ThinkCentre A57",
 914                .matches = {
 915                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
 916                        DMI_MATCH(DMI_PRODUCT_NAME, "97027RG"),
 917                },
 918        },
 919        { }
 920};
 921
 922static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv)
 923{
 924        struct intel_opregion *opregion = &dev_priv->opregion;
 925        const struct firmware *fw = NULL;
 926        const char *name = i915_modparams.vbt_firmware;
 927        int ret;
 928
 929        if (!name || !*name)
 930                return -ENOENT;
 931
 932        ret = request_firmware(&fw, name, &dev_priv->drm.pdev->dev);
 933        if (ret) {
 934                DRM_ERROR("Requesting VBT firmware \"%s\" failed (%d)\n",
 935                          name, ret);
 936                return ret;
 937        }
 938
 939        if (intel_bios_is_valid_vbt(fw->data, fw->size)) {
 940                opregion->vbt_firmware = kmemdup(fw->data, fw->size, GFP_KERNEL);
 941                if (opregion->vbt_firmware) {
 942                        DRM_DEBUG_KMS("Found valid VBT firmware \"%s\"\n", name);
 943                        opregion->vbt = opregion->vbt_firmware;
 944                        opregion->vbt_size = fw->size;
 945                        ret = 0;
 946                } else {
 947                        ret = -ENOMEM;
 948                }
 949        } else {
 950                DRM_DEBUG_KMS("Invalid VBT firmware \"%s\"\n", name);
 951                ret = -EINVAL;
 952        }
 953
 954        release_firmware(fw);
 955
 956        return ret;
 957}
 958
 959int intel_opregion_setup(struct drm_i915_private *dev_priv)
 960{
 961        struct intel_opregion *opregion = &dev_priv->opregion;
 962        struct pci_dev *pdev = dev_priv->drm.pdev;
 963        u32 asls, mboxes;
 964        char buf[sizeof(OPREGION_SIGNATURE)];
 965        int err = 0;
 966        void *base;
 967        const void *vbt;
 968        u32 vbt_size;
 969
 970        BUILD_BUG_ON(sizeof(struct opregion_header) != 0x100);
 971        BUILD_BUG_ON(sizeof(struct opregion_acpi) != 0x100);
 972        BUILD_BUG_ON(sizeof(struct opregion_swsci) != 0x100);
 973        BUILD_BUG_ON(sizeof(struct opregion_asle) != 0x100);
 974        BUILD_BUG_ON(sizeof(struct opregion_asle_ext) != 0x400);
 975
 976        pci_read_config_dword(pdev, ASLS, &asls);
 977        DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
 978        if (asls == 0) {
 979                DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
 980                return -ENOTSUPP;
 981        }
 982
 983        INIT_WORK(&opregion->asle_work, asle_work);
 984
 985        base = memremap(asls, OPREGION_SIZE, MEMREMAP_WB);
 986        if (!base)
 987                return -ENOMEM;
 988
 989        memcpy(buf, base, sizeof(buf));
 990
 991        if (memcmp(buf, OPREGION_SIGNATURE, 16)) {
 992                DRM_DEBUG_DRIVER("opregion signature mismatch\n");
 993                err = -EINVAL;
 994                goto err_out;
 995        }
 996        opregion->header = base;
 997        opregion->lid_state = base + ACPI_CLID;
 998
 999        mboxes = opregion->header->mboxes;
1000        if (mboxes & MBOX_ACPI) {
1001                DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
1002                opregion->acpi = base + OPREGION_ACPI_OFFSET;
1003        }
1004
1005        if (mboxes & MBOX_SWSCI) {
1006                DRM_DEBUG_DRIVER("SWSCI supported\n");
1007                opregion->swsci = base + OPREGION_SWSCI_OFFSET;
1008                swsci_setup(dev_priv);
1009        }
1010
1011        if (mboxes & MBOX_ASLE) {
1012                DRM_DEBUG_DRIVER("ASLE supported\n");
1013                opregion->asle = base + OPREGION_ASLE_OFFSET;
1014
1015                opregion->asle->ardy = ASLE_ARDY_NOT_READY;
1016        }
1017
1018        if (mboxes & MBOX_ASLE_EXT)
1019                DRM_DEBUG_DRIVER("ASLE extension supported\n");
1020
1021        if (intel_load_vbt_firmware(dev_priv) == 0)
1022                goto out;
1023
1024        if (dmi_check_system(intel_no_opregion_vbt))
1025                goto out;
1026
1027        if (opregion->header->opregion_ver >= 2 && opregion->asle &&
1028            opregion->asle->rvda && opregion->asle->rvds) {
1029                opregion->rvda = memremap(opregion->asle->rvda,
1030                                          opregion->asle->rvds,
1031                                          MEMREMAP_WB);
1032                vbt = opregion->rvda;
1033                vbt_size = opregion->asle->rvds;
1034                if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
1035                        DRM_DEBUG_KMS("Found valid VBT in ACPI OpRegion (RVDA)\n");
1036                        opregion->vbt = vbt;
1037                        opregion->vbt_size = vbt_size;
1038                        goto out;
1039                } else {
1040                        DRM_DEBUG_KMS("Invalid VBT in ACPI OpRegion (RVDA)\n");
1041                }
1042        }
1043
1044        vbt = base + OPREGION_VBT_OFFSET;
1045        /*
1046         * The VBT specification says that if the ASLE ext mailbox is not used
1047         * its area is reserved, but on some CHT boards the VBT extends into the
1048         * ASLE ext area. Allow this even though it is against the spec, so we
1049         * do not end up rejecting the VBT on those boards (and end up not
1050         * finding the LCD panel because of this).
1051         */
1052        vbt_size = (mboxes & MBOX_ASLE_EXT) ?
1053                OPREGION_ASLE_EXT_OFFSET : OPREGION_SIZE;
1054        vbt_size -= OPREGION_VBT_OFFSET;
1055        if (intel_bios_is_valid_vbt(vbt, vbt_size)) {
1056                DRM_DEBUG_KMS("Found valid VBT in ACPI OpRegion (Mailbox #4)\n");
1057                opregion->vbt = vbt;
1058                opregion->vbt_size = vbt_size;
1059        } else {
1060                DRM_DEBUG_KMS("Invalid VBT in ACPI OpRegion (Mailbox #4)\n");
1061        }
1062
1063out:
1064        return 0;
1065
1066err_out:
1067        memunmap(base);
1068        return err;
1069}
1070
1071static int intel_use_opregion_panel_type_callback(const struct dmi_system_id *id)
1072{
1073        DRM_INFO("Using panel type from OpRegion on %s\n", id->ident);
1074        return 1;
1075}
1076
1077static const struct dmi_system_id intel_use_opregion_panel_type[] = {
1078        {
1079                .callback = intel_use_opregion_panel_type_callback,
1080                .ident = "Conrac GmbH IX45GM2",
1081                .matches = {DMI_MATCH(DMI_SYS_VENDOR, "Conrac GmbH"),
1082                            DMI_MATCH(DMI_PRODUCT_NAME, "IX45GM2"),
1083                },
1084        },
1085        { }
1086};
1087
1088int
1089intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
1090{
1091        u32 panel_details;
1092        int ret;
1093
1094        ret = swsci(dev_priv, SWSCI_GBDA_PANEL_DETAILS, 0x0, &panel_details);
1095        if (ret) {
1096                DRM_DEBUG_KMS("Failed to get panel details from OpRegion (%d)\n",
1097                              ret);
1098                return ret;
1099        }
1100
1101        ret = (panel_details >> 8) & 0xff;
1102        if (ret > 0x10) {
1103                DRM_DEBUG_KMS("Invalid OpRegion panel type 0x%x\n", ret);
1104                return -EINVAL;
1105        }
1106
1107        /* fall back to VBT panel type? */
1108        if (ret == 0x0) {
1109                DRM_DEBUG_KMS("No panel type in OpRegion\n");
1110                return -ENODEV;
1111        }
1112
1113        /*
1114         * So far we know that some machined must use it, others must not use it.
1115         * There doesn't seem to be any way to determine which way to go, except
1116         * via a quirk list :(
1117         */
1118        if (!dmi_check_system(intel_use_opregion_panel_type)) {
1119                DRM_DEBUG_KMS("Ignoring OpRegion panel type (%d)\n", ret - 1);
1120                return -ENODEV;
1121        }
1122
1123        return ret - 1;
1124}
1125