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 <acpi/video.h>
  30
  31#include <drm/drmP.h>
  32#include <drm/i915_drm.h>
  33#include "i915_drv.h"
  34#include "intel_drv.h"
  35
  36#define PCI_ASLE                0xe4
  37#define PCI_ASLS                0xfc
  38#define PCI_SWSCI               0xe8
  39#define PCI_SWSCI_SCISEL        (1 << 15)
  40#define PCI_SWSCI_GSSCIE        (1 << 0)
  41
  42#define OPREGION_HEADER_OFFSET 0
  43#define OPREGION_ACPI_OFFSET   0x100
  44#define   ACPI_CLID 0x01ac /* current lid state indicator */
  45#define   ACPI_CDCK 0x01b0 /* current docking state indicator */
  46#define OPREGION_SWSCI_OFFSET  0x200
  47#define OPREGION_ASLE_OFFSET   0x300
  48#define OPREGION_VBT_OFFSET    0x400
  49
  50#define OPREGION_SIGNATURE "IntelGraphicsMem"
  51#define MBOX_ACPI      (1<<0)
  52#define MBOX_SWSCI     (1<<1)
  53#define MBOX_ASLE      (1<<2)
  54#define MBOX_ASLE_EXT  (1<<4)
  55
  56struct opregion_header {
  57        u8 signature[16];
  58        u32 size;
  59        u32 opregion_ver;
  60        u8 bios_ver[32];
  61        u8 vbios_ver[16];
  62        u8 driver_ver[16];
  63        u32 mboxes;
  64        u32 driver_model;
  65        u32 pcon;
  66        u8 dver[32];
  67        u8 rsvd[124];
  68} __packed;
  69
  70/* OpRegion mailbox #1: public ACPI methods */
  71struct opregion_acpi {
  72        u32 drdy;       /* driver readiness */
  73        u32 csts;       /* notification status */
  74        u32 cevt;       /* current event */
  75        u8 rsvd1[20];
  76        u32 didl[8];    /* supported display devices ID list */
  77        u32 cpdl[8];    /* currently presented display list */
  78        u32 cadl[8];    /* currently active display list */
  79        u32 nadl[8];    /* next active devices list */
  80        u32 aslp;       /* ASL sleep time-out */
  81        u32 tidx;       /* toggle table index */
  82        u32 chpd;       /* current hotplug enable indicator */
  83        u32 clid;       /* current lid state*/
  84        u32 cdck;       /* current docking state */
  85        u32 sxsw;       /* Sx state resume */
  86        u32 evts;       /* ASL supported events */
  87        u32 cnot;       /* current OS notification */
  88        u32 nrdy;       /* driver status */
  89        u32 did2[7];    /* extended supported display devices ID list */
  90        u32 cpd2[7];    /* extended attached display devices list */
  91        u8 rsvd2[4];
  92} __packed;
  93
  94/* OpRegion mailbox #2: SWSCI */
  95struct opregion_swsci {
  96        u32 scic;       /* SWSCI command|status|data */
  97        u32 parm;       /* command parameters */
  98        u32 dslp;       /* driver sleep time-out */
  99        u8 rsvd[244];
 100} __packed;
 101
 102/* OpRegion mailbox #3: ASLE */
 103struct opregion_asle {
 104        u32 ardy;       /* driver readiness */
 105        u32 aslc;       /* ASLE interrupt command */
 106        u32 tche;       /* technology enabled indicator */
 107        u32 alsi;       /* current ALS illuminance reading */
 108        u32 bclp;       /* backlight brightness to set */
 109        u32 pfit;       /* panel fitting state */
 110        u32 cblv;       /* current brightness level */
 111        u16 bclm[20];   /* backlight level duty cycle mapping table */
 112        u32 cpfm;       /* current panel fitting mode */
 113        u32 epfm;       /* enabled panel fitting modes */
 114        u8 plut[74];    /* panel LUT and identifier */
 115        u32 pfmb;       /* PWM freq and min brightness */
 116        u32 cddv;       /* color correction default values */
 117        u32 pcft;       /* power conservation features */
 118        u32 srot;       /* supported rotation angles */
 119        u32 iuer;       /* IUER events */
 120        u64 fdss;
 121        u32 fdsp;
 122        u32 stat;
 123        u8 rsvd[70];
 124} __packed;
 125
 126/* Driver readiness indicator */
 127#define ASLE_ARDY_READY         (1 << 0)
 128#define ASLE_ARDY_NOT_READY     (0 << 0)
 129
 130/* ASLE Interrupt Command (ASLC) bits */
 131#define ASLC_SET_ALS_ILLUM              (1 << 0)
 132#define ASLC_SET_BACKLIGHT              (1 << 1)
 133#define ASLC_SET_PFIT                   (1 << 2)
 134#define ASLC_SET_PWM_FREQ               (1 << 3)
 135#define ASLC_SUPPORTED_ROTATION_ANGLES  (1 << 4)
 136#define ASLC_BUTTON_ARRAY               (1 << 5)
 137#define ASLC_CONVERTIBLE_INDICATOR      (1 << 6)
 138#define ASLC_DOCKING_INDICATOR          (1 << 7)
 139#define ASLC_ISCT_STATE_CHANGE          (1 << 8)
 140#define ASLC_REQ_MSK                    0x1ff
 141/* response bits */
 142#define ASLC_ALS_ILLUM_FAILED           (1 << 10)
 143#define ASLC_BACKLIGHT_FAILED           (1 << 12)
 144#define ASLC_PFIT_FAILED                (1 << 14)
 145#define ASLC_PWM_FREQ_FAILED            (1 << 16)
 146#define ASLC_ROTATION_ANGLES_FAILED     (1 << 18)
 147#define ASLC_BUTTON_ARRAY_FAILED        (1 << 20)
 148#define ASLC_CONVERTIBLE_FAILED         (1 << 22)
 149#define ASLC_DOCKING_FAILED             (1 << 24)
 150#define ASLC_ISCT_STATE_FAILED          (1 << 26)
 151
 152/* Technology enabled indicator */
 153#define ASLE_TCHE_ALS_EN        (1 << 0)
 154#define ASLE_TCHE_BLC_EN        (1 << 1)
 155#define ASLE_TCHE_PFIT_EN       (1 << 2)
 156#define ASLE_TCHE_PFMB_EN       (1 << 3)
 157
 158/* ASLE backlight brightness to set */
 159#define ASLE_BCLP_VALID                (1<<31)
 160#define ASLE_BCLP_MSK          (~(1<<31))
 161
 162/* ASLE panel fitting request */
 163#define ASLE_PFIT_VALID         (1<<31)
 164#define ASLE_PFIT_CENTER (1<<0)
 165#define ASLE_PFIT_STRETCH_TEXT (1<<1)
 166#define ASLE_PFIT_STRETCH_GFX (1<<2)
 167
 168/* PWM frequency and minimum brightness */
 169#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
 170#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
 171#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
 172#define ASLE_PFMB_PWM_VALID (1<<31)
 173
 174#define ASLE_CBLV_VALID         (1<<31)
 175
 176/* IUER */
 177#define ASLE_IUER_DOCKING               (1 << 7)
 178#define ASLE_IUER_CONVERTIBLE           (1 << 6)
 179#define ASLE_IUER_ROTATION_LOCK_BTN     (1 << 4)
 180#define ASLE_IUER_VOLUME_DOWN_BTN       (1 << 3)
 181#define ASLE_IUER_VOLUME_UP_BTN         (1 << 2)
 182#define ASLE_IUER_WINDOWS_BTN           (1 << 1)
 183#define ASLE_IUER_POWER_BTN             (1 << 0)
 184
 185/* Software System Control Interrupt (SWSCI) */
 186#define SWSCI_SCIC_INDICATOR            (1 << 0)
 187#define SWSCI_SCIC_MAIN_FUNCTION_SHIFT  1
 188#define SWSCI_SCIC_MAIN_FUNCTION_MASK   (0xf << 1)
 189#define SWSCI_SCIC_SUB_FUNCTION_SHIFT   8
 190#define SWSCI_SCIC_SUB_FUNCTION_MASK    (0xff << 8)
 191#define SWSCI_SCIC_EXIT_PARAMETER_SHIFT 8
 192#define SWSCI_SCIC_EXIT_PARAMETER_MASK  (0xff << 8)
 193#define SWSCI_SCIC_EXIT_STATUS_SHIFT    5
 194#define SWSCI_SCIC_EXIT_STATUS_MASK     (7 << 5)
 195#define SWSCI_SCIC_EXIT_STATUS_SUCCESS  1
 196
 197#define SWSCI_FUNCTION_CODE(main, sub) \
 198        ((main) << SWSCI_SCIC_MAIN_FUNCTION_SHIFT | \
 199         (sub) << SWSCI_SCIC_SUB_FUNCTION_SHIFT)
 200
 201/* SWSCI: Get BIOS Data (GBDA) */
 202#define SWSCI_GBDA                      4
 203#define SWSCI_GBDA_SUPPORTED_CALLS      SWSCI_FUNCTION_CODE(SWSCI_GBDA, 0)
 204#define SWSCI_GBDA_REQUESTED_CALLBACKS  SWSCI_FUNCTION_CODE(SWSCI_GBDA, 1)
 205#define SWSCI_GBDA_BOOT_DISPLAY_PREF    SWSCI_FUNCTION_CODE(SWSCI_GBDA, 4)
 206#define SWSCI_GBDA_PANEL_DETAILS        SWSCI_FUNCTION_CODE(SWSCI_GBDA, 5)
 207#define SWSCI_GBDA_TV_STANDARD          SWSCI_FUNCTION_CODE(SWSCI_GBDA, 6)
 208#define SWSCI_GBDA_INTERNAL_GRAPHICS    SWSCI_FUNCTION_CODE(SWSCI_GBDA, 7)
 209#define SWSCI_GBDA_SPREAD_SPECTRUM      SWSCI_FUNCTION_CODE(SWSCI_GBDA, 10)
 210
 211/* SWSCI: System BIOS Callbacks (SBCB) */
 212#define SWSCI_SBCB                      6
 213#define SWSCI_SBCB_SUPPORTED_CALLBACKS  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 0)
 214#define SWSCI_SBCB_INIT_COMPLETION      SWSCI_FUNCTION_CODE(SWSCI_SBCB, 1)
 215#define SWSCI_SBCB_PRE_HIRES_SET_MODE   SWSCI_FUNCTION_CODE(SWSCI_SBCB, 3)
 216#define SWSCI_SBCB_POST_HIRES_SET_MODE  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 4)
 217#define SWSCI_SBCB_DISPLAY_SWITCH       SWSCI_FUNCTION_CODE(SWSCI_SBCB, 5)
 218#define SWSCI_SBCB_SET_TV_FORMAT        SWSCI_FUNCTION_CODE(SWSCI_SBCB, 6)
 219#define SWSCI_SBCB_ADAPTER_POWER_STATE  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 7)
 220#define SWSCI_SBCB_DISPLAY_POWER_STATE  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 8)
 221#define SWSCI_SBCB_SET_BOOT_DISPLAY     SWSCI_FUNCTION_CODE(SWSCI_SBCB, 9)
 222#define SWSCI_SBCB_SET_PANEL_DETAILS    SWSCI_FUNCTION_CODE(SWSCI_SBCB, 10)
 223#define SWSCI_SBCB_SET_INTERNAL_GFX     SWSCI_FUNCTION_CODE(SWSCI_SBCB, 11)
 224#define SWSCI_SBCB_POST_HIRES_TO_DOS_FS SWSCI_FUNCTION_CODE(SWSCI_SBCB, 16)
 225#define SWSCI_SBCB_SUSPEND_RESUME       SWSCI_FUNCTION_CODE(SWSCI_SBCB, 17)
 226#define SWSCI_SBCB_SET_SPREAD_SPECTRUM  SWSCI_FUNCTION_CODE(SWSCI_SBCB, 18)
 227#define SWSCI_SBCB_POST_VBE_PM          SWSCI_FUNCTION_CODE(SWSCI_SBCB, 19)
 228#define SWSCI_SBCB_ENABLE_DISABLE_AUDIO SWSCI_FUNCTION_CODE(SWSCI_SBCB, 21)
 229
 230#define ACPI_OTHER_OUTPUT (0<<8)
 231#define ACPI_VGA_OUTPUT (1<<8)
 232#define ACPI_TV_OUTPUT (2<<8)
 233#define ACPI_DIGITAL_OUTPUT (3<<8)
 234#define ACPI_LVDS_OUTPUT (4<<8)
 235
 236#define MAX_DSLP        1500
 237
 238#ifdef CONFIG_ACPI
 239static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
 240{
 241        struct drm_i915_private *dev_priv = dev->dev_private;
 242        struct opregion_swsci *swsci = dev_priv->opregion.swsci;
 243        u32 main_function, sub_function, scic;
 244        u16 pci_swsci;
 245        u32 dslp;
 246
 247        if (!swsci)
 248                return -ENODEV;
 249
 250        main_function = (function & SWSCI_SCIC_MAIN_FUNCTION_MASK) >>
 251                SWSCI_SCIC_MAIN_FUNCTION_SHIFT;
 252        sub_function = (function & SWSCI_SCIC_SUB_FUNCTION_MASK) >>
 253                SWSCI_SCIC_SUB_FUNCTION_SHIFT;
 254
 255        /* Check if we can call the function. See swsci_setup for details. */
 256        if (main_function == SWSCI_SBCB) {
 257                if ((dev_priv->opregion.swsci_sbcb_sub_functions &
 258                     (1 << sub_function)) == 0)
 259                        return -EINVAL;
 260        } else if (main_function == SWSCI_GBDA) {
 261                if ((dev_priv->opregion.swsci_gbda_sub_functions &
 262                     (1 << sub_function)) == 0)
 263                        return -EINVAL;
 264        }
 265
 266        /* Driver sleep timeout in ms. */
 267        dslp = swsci->dslp;
 268        if (!dslp) {
 269                /* The spec says 2ms should be the default, but it's too small
 270                 * for some machines. */
 271                dslp = 50;
 272        } else if (dslp > MAX_DSLP) {
 273                /* Hey bios, trust must be earned. */
 274                DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, "
 275                              "using %u ms instead\n", dslp, MAX_DSLP);
 276                dslp = MAX_DSLP;
 277        }
 278
 279        /* The spec tells us to do this, but we are the only user... */
 280        scic = swsci->scic;
 281        if (scic & SWSCI_SCIC_INDICATOR) {
 282                DRM_DEBUG_DRIVER("SWSCI request already in progress\n");
 283                return -EBUSY;
 284        }
 285
 286        scic = function | SWSCI_SCIC_INDICATOR;
 287
 288        swsci->parm = parm;
 289        swsci->scic = scic;
 290
 291        /* Ensure SCI event is selected and event trigger is cleared. */
 292        pci_read_config_word(dev->pdev, PCI_SWSCI, &pci_swsci);
 293        if (!(pci_swsci & PCI_SWSCI_SCISEL) || (pci_swsci & PCI_SWSCI_GSSCIE)) {
 294                pci_swsci |= PCI_SWSCI_SCISEL;
 295                pci_swsci &= ~PCI_SWSCI_GSSCIE;
 296                pci_write_config_word(dev->pdev, PCI_SWSCI, pci_swsci);
 297        }
 298
 299        /* Use event trigger to tell bios to check the mail. */
 300        pci_swsci |= PCI_SWSCI_GSSCIE;
 301        pci_write_config_word(dev->pdev, PCI_SWSCI, pci_swsci);
 302
 303        /* Poll for the result. */
 304#define C (((scic = swsci->scic) & SWSCI_SCIC_INDICATOR) == 0)
 305        if (wait_for(C, dslp)) {
 306                DRM_DEBUG_DRIVER("SWSCI request timed out\n");
 307                return -ETIMEDOUT;
 308        }
 309
 310        scic = (scic & SWSCI_SCIC_EXIT_STATUS_MASK) >>
 311                SWSCI_SCIC_EXIT_STATUS_SHIFT;
 312
 313        /* Note: scic == 0 is an error! */
 314        if (scic != SWSCI_SCIC_EXIT_STATUS_SUCCESS) {
 315                DRM_DEBUG_DRIVER("SWSCI request error %u\n", scic);
 316                return -EIO;
 317        }
 318
 319        if (parm_out)
 320                *parm_out = swsci->parm;
 321
 322        return 0;
 323
 324#undef C
 325}
 326
 327#define DISPLAY_TYPE_CRT                        0
 328#define DISPLAY_TYPE_TV                         1
 329#define DISPLAY_TYPE_EXTERNAL_FLAT_PANEL        2
 330#define DISPLAY_TYPE_INTERNAL_FLAT_PANEL        3
 331
 332int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
 333                                  bool enable)
 334{
 335        struct drm_device *dev = intel_encoder->base.dev;
 336        u32 parm = 0;
 337        u32 type = 0;
 338        u32 port;
 339
 340        /* don't care about old stuff for now */
 341        if (!HAS_DDI(dev))
 342                return 0;
 343
 344        if (intel_encoder->type == INTEL_OUTPUT_DSI)
 345                port = 0;
 346        else
 347                port = intel_ddi_get_encoder_port(intel_encoder);
 348
 349        if (port == PORT_E)  {
 350                port = 0;
 351        } else {
 352                parm |= 1 << port;
 353                port++;
 354        }
 355
 356        if (!enable)
 357                parm |= 4 << 8;
 358
 359        switch (intel_encoder->type) {
 360        case INTEL_OUTPUT_ANALOG:
 361                type = DISPLAY_TYPE_CRT;
 362                break;
 363        case INTEL_OUTPUT_UNKNOWN:
 364        case INTEL_OUTPUT_DISPLAYPORT:
 365        case INTEL_OUTPUT_HDMI:
 366        case INTEL_OUTPUT_DP_MST:
 367                type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL;
 368                break;
 369        case INTEL_OUTPUT_EDP:
 370        case INTEL_OUTPUT_DSI:
 371                type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL;
 372                break;
 373        default:
 374                WARN_ONCE(1, "unsupported intel_encoder type %d\n",
 375                          intel_encoder->type);
 376                return -EINVAL;
 377        }
 378
 379        parm |= type << (16 + port * 3);
 380
 381        return swsci(dev, SWSCI_SBCB_DISPLAY_POWER_STATE, parm, NULL);
 382}
 383
 384static const struct {
 385        pci_power_t pci_power_state;
 386        u32 parm;
 387} power_state_map[] = {
 388        { PCI_D0,       0x00 },
 389        { PCI_D1,       0x01 },
 390        { PCI_D2,       0x02 },
 391        { PCI_D3hot,    0x04 },
 392        { PCI_D3cold,   0x04 },
 393};
 394
 395int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state)
 396{
 397        int i;
 398
 399        if (!HAS_DDI(dev))
 400                return 0;
 401
 402        for (i = 0; i < ARRAY_SIZE(power_state_map); i++) {
 403                if (state == power_state_map[i].pci_power_state)
 404                        return swsci(dev, SWSCI_SBCB_ADAPTER_POWER_STATE,
 405                                     power_state_map[i].parm, NULL);
 406        }
 407
 408        return -EINVAL;
 409}
 410
 411static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 412{
 413        struct drm_i915_private *dev_priv = dev->dev_private;
 414        struct intel_connector *intel_connector;
 415        struct opregion_asle *asle = dev_priv->opregion.asle;
 416
 417        DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
 418
 419        if (acpi_video_get_backlight_type() == acpi_backlight_native) {
 420                DRM_DEBUG_KMS("opregion backlight request ignored\n");
 421                return 0;
 422        }
 423
 424        if (!(bclp & ASLE_BCLP_VALID))
 425                return ASLC_BACKLIGHT_FAILED;
 426
 427        bclp &= ASLE_BCLP_MSK;
 428        if (bclp > 255)
 429                return ASLC_BACKLIGHT_FAILED;
 430
 431        drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 432
 433        /*
 434         * Update backlight on all connectors that support backlight (usually
 435         * only one).
 436         */
 437        DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp);
 438        list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head)
 439                intel_panel_set_backlight_acpi(intel_connector, bclp, 255);
 440        asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID;
 441
 442        drm_modeset_unlock(&dev->mode_config.connection_mutex);
 443
 444
 445        return 0;
 446}
 447
 448static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
 449{
 450        /* alsi is the current ALS reading in lux. 0 indicates below sensor
 451           range, 0xffff indicates above sensor range. 1-0xfffe are valid */
 452        DRM_DEBUG_DRIVER("Illum is not supported\n");
 453        return ASLC_ALS_ILLUM_FAILED;
 454}
 455
 456static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
 457{
 458        DRM_DEBUG_DRIVER("PWM freq is not supported\n");
 459        return ASLC_PWM_FREQ_FAILED;
 460}
 461
 462static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
 463{
 464        /* Panel fitting is currently controlled by the X code, so this is a
 465           noop until modesetting support works fully */
 466        DRM_DEBUG_DRIVER("Pfit is not supported\n");
 467        return ASLC_PFIT_FAILED;
 468}
 469
 470static u32 asle_set_supported_rotation_angles(struct drm_device *dev, u32 srot)
 471{
 472        DRM_DEBUG_DRIVER("SROT is not supported\n");
 473        return ASLC_ROTATION_ANGLES_FAILED;
 474}
 475
 476static u32 asle_set_button_array(struct drm_device *dev, u32 iuer)
 477{
 478        if (!iuer)
 479                DRM_DEBUG_DRIVER("Button array event is not supported (nothing)\n");
 480        if (iuer & ASLE_IUER_ROTATION_LOCK_BTN)
 481                DRM_DEBUG_DRIVER("Button array event is not supported (rotation lock)\n");
 482        if (iuer & ASLE_IUER_VOLUME_DOWN_BTN)
 483                DRM_DEBUG_DRIVER("Button array event is not supported (volume down)\n");
 484        if (iuer & ASLE_IUER_VOLUME_UP_BTN)
 485                DRM_DEBUG_DRIVER("Button array event is not supported (volume up)\n");
 486        if (iuer & ASLE_IUER_WINDOWS_BTN)
 487                DRM_DEBUG_DRIVER("Button array event is not supported (windows)\n");
 488        if (iuer & ASLE_IUER_POWER_BTN)
 489                DRM_DEBUG_DRIVER("Button array event is not supported (power)\n");
 490
 491        return ASLC_BUTTON_ARRAY_FAILED;
 492}
 493
 494static u32 asle_set_convertible(struct drm_device *dev, u32 iuer)
 495{
 496        if (iuer & ASLE_IUER_CONVERTIBLE)
 497                DRM_DEBUG_DRIVER("Convertible is not supported (clamshell)\n");
 498        else
 499                DRM_DEBUG_DRIVER("Convertible is not supported (slate)\n");
 500
 501        return ASLC_CONVERTIBLE_FAILED;
 502}
 503
 504static u32 asle_set_docking(struct drm_device *dev, u32 iuer)
 505{
 506        if (iuer & ASLE_IUER_DOCKING)
 507                DRM_DEBUG_DRIVER("Docking is not supported (docked)\n");
 508        else
 509                DRM_DEBUG_DRIVER("Docking is not supported (undocked)\n");
 510
 511        return ASLC_DOCKING_FAILED;
 512}
 513
 514static u32 asle_isct_state(struct drm_device *dev)
 515{
 516        DRM_DEBUG_DRIVER("ISCT is not supported\n");
 517        return ASLC_ISCT_STATE_FAILED;
 518}
 519
 520static void asle_work(struct work_struct *work)
 521{
 522        struct intel_opregion *opregion =
 523                container_of(work, struct intel_opregion, asle_work);
 524        struct drm_i915_private *dev_priv =
 525                container_of(opregion, struct drm_i915_private, opregion);
 526        struct drm_device *dev = dev_priv->dev;
 527        struct opregion_asle *asle = dev_priv->opregion.asle;
 528        u32 aslc_stat = 0;
 529        u32 aslc_req;
 530
 531        if (!asle)
 532                return;
 533
 534        aslc_req = asle->aslc;
 535
 536        if (!(aslc_req & ASLC_REQ_MSK)) {
 537                DRM_DEBUG_DRIVER("No request on ASLC interrupt 0x%08x\n",
 538                                 aslc_req);
 539                return;
 540        }
 541
 542        if (aslc_req & ASLC_SET_ALS_ILLUM)
 543                aslc_stat |= asle_set_als_illum(dev, asle->alsi);
 544
 545        if (aslc_req & ASLC_SET_BACKLIGHT)
 546                aslc_stat |= asle_set_backlight(dev, asle->bclp);
 547
 548        if (aslc_req & ASLC_SET_PFIT)
 549                aslc_stat |= asle_set_pfit(dev, asle->pfit);
 550
 551        if (aslc_req & ASLC_SET_PWM_FREQ)
 552                aslc_stat |= asle_set_pwm_freq(dev, asle->pfmb);
 553
 554        if (aslc_req & ASLC_SUPPORTED_ROTATION_ANGLES)
 555                aslc_stat |= asle_set_supported_rotation_angles(dev,
 556                                                        asle->srot);
 557
 558        if (aslc_req & ASLC_BUTTON_ARRAY)
 559                aslc_stat |= asle_set_button_array(dev, asle->iuer);
 560
 561        if (aslc_req & ASLC_CONVERTIBLE_INDICATOR)
 562                aslc_stat |= asle_set_convertible(dev, asle->iuer);
 563
 564        if (aslc_req & ASLC_DOCKING_INDICATOR)
 565                aslc_stat |= asle_set_docking(dev, asle->iuer);
 566
 567        if (aslc_req & ASLC_ISCT_STATE_CHANGE)
 568                aslc_stat |= asle_isct_state(dev);
 569
 570        asle->aslc = aslc_stat;
 571}
 572
 573void intel_opregion_asle_intr(struct drm_device *dev)
 574{
 575        struct drm_i915_private *dev_priv = dev->dev_private;
 576
 577        if (dev_priv->opregion.asle)
 578                schedule_work(&dev_priv->opregion.asle_work);
 579}
 580
 581#define ACPI_EV_DISPLAY_SWITCH (1<<0)
 582#define ACPI_EV_LID            (1<<1)
 583#define ACPI_EV_DOCK           (1<<2)
 584
 585static struct intel_opregion *system_opregion;
 586
 587static int intel_opregion_video_event(struct notifier_block *nb,
 588                                      unsigned long val, void *data)
 589{
 590        /* The only video events relevant to opregion are 0x80. These indicate
 591           either a docking event, lid switch or display switch request. In
 592           Linux, these are handled by the dock, button and video drivers.
 593        */
 594
 595        struct acpi_bus_event *event = data;
 596        struct opregion_acpi *acpi;
 597        int ret = NOTIFY_OK;
 598
 599        if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
 600                return NOTIFY_DONE;
 601
 602        if (!system_opregion)
 603                return NOTIFY_DONE;
 604
 605        acpi = system_opregion->acpi;
 606
 607        if (event->type == 0x80 && ((acpi->cevt & 1) == 0))
 608                ret = NOTIFY_BAD;
 609
 610        acpi->csts = 0;
 611
 612        return ret;
 613}
 614
 615static struct notifier_block intel_opregion_notifier = {
 616        .notifier_call = intel_opregion_video_event,
 617};
 618
 619/*
 620 * Initialise the DIDL field in opregion. This passes a list of devices to
 621 * the firmware. Values are defined by section B.4.2 of the ACPI specification
 622 * (version 3)
 623 */
 624
 625static u32 get_did(struct intel_opregion *opregion, int i)
 626{
 627        u32 did;
 628
 629        if (i < ARRAY_SIZE(opregion->acpi->didl)) {
 630                did = opregion->acpi->didl[i];
 631        } else {
 632                i -= ARRAY_SIZE(opregion->acpi->didl);
 633
 634                if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2)))
 635                        return 0;
 636
 637                did = opregion->acpi->did2[i];
 638        }
 639
 640        return did;
 641}
 642
 643static void set_did(struct intel_opregion *opregion, int i, u32 val)
 644{
 645        if (i < ARRAY_SIZE(opregion->acpi->didl)) {
 646                opregion->acpi->didl[i] = val;
 647        } else {
 648                i -= ARRAY_SIZE(opregion->acpi->didl);
 649
 650                if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2)))
 651                        return;
 652
 653                opregion->acpi->did2[i] = val;
 654        }
 655}
 656
 657static void intel_didl_outputs(struct drm_device *dev)
 658{
 659        struct drm_i915_private *dev_priv = dev->dev_private;
 660        struct intel_opregion *opregion = &dev_priv->opregion;
 661        struct drm_connector *connector;
 662        acpi_handle handle;
 663        struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
 664        unsigned long long device_id;
 665        acpi_status status;
 666        u32 temp, max_outputs;
 667        int i = 0;
 668
 669        handle = ACPI_HANDLE(&dev->pdev->dev);
 670        if (!handle || acpi_bus_get_device(handle, &acpi_dev))
 671                return;
 672
 673        if (acpi_is_video_device(handle))
 674                acpi_video_bus = acpi_dev;
 675        else {
 676                list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
 677                        if (acpi_is_video_device(acpi_cdev->handle)) {
 678                                acpi_video_bus = acpi_cdev;
 679                                break;
 680                        }
 681                }
 682        }
 683
 684        if (!acpi_video_bus) {
 685                DRM_ERROR("No ACPI video bus found\n");
 686                return;
 687        }
 688
 689        /*
 690         * In theory, did2, the extended didl, gets added at opregion version
 691         * 3.0. In practice, however, we're supposed to set it for earlier
 692         * versions as well, since a BIOS that doesn't understand did2 should
 693         * not look at it anyway. Use a variable so we can tweak this if a need
 694         * arises later.
 695         */
 696        max_outputs = ARRAY_SIZE(opregion->acpi->didl) +
 697                ARRAY_SIZE(opregion->acpi->did2);
 698
 699        list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
 700                if (i >= max_outputs) {
 701                        DRM_DEBUG_KMS("More than %u outputs detected via ACPI\n",
 702                                      max_outputs);
 703                        return;
 704                }
 705                status = acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
 706                                               NULL, &device_id);
 707                if (ACPI_SUCCESS(status)) {
 708                        if (!device_id)
 709                                goto blind_set;
 710                        set_did(opregion, i++, (u32)(device_id & 0x0f0f));
 711                }
 712        }
 713
 714end:
 715        DRM_DEBUG_KMS("%d outputs detected\n", i);
 716
 717        /* If fewer than max outputs, the list must be null terminated */
 718        if (i < max_outputs)
 719                set_did(opregion, i, 0);
 720        return;
 721
 722blind_set:
 723        i = 0;
 724        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 725                int output_type = ACPI_OTHER_OUTPUT;
 726                if (i >= max_outputs) {
 727                        DRM_DEBUG_KMS("More than %u outputs in connector list\n",
 728                                      max_outputs);
 729                        return;
 730                }
 731                switch (connector->connector_type) {
 732                case DRM_MODE_CONNECTOR_VGA:
 733                case DRM_MODE_CONNECTOR_DVIA:
 734                        output_type = ACPI_VGA_OUTPUT;
 735                        break;
 736                case DRM_MODE_CONNECTOR_Composite:
 737                case DRM_MODE_CONNECTOR_SVIDEO:
 738                case DRM_MODE_CONNECTOR_Component:
 739                case DRM_MODE_CONNECTOR_9PinDIN:
 740                        output_type = ACPI_TV_OUTPUT;
 741                        break;
 742                case DRM_MODE_CONNECTOR_DVII:
 743                case DRM_MODE_CONNECTOR_DVID:
 744                case DRM_MODE_CONNECTOR_DisplayPort:
 745                case DRM_MODE_CONNECTOR_HDMIA:
 746                case DRM_MODE_CONNECTOR_HDMIB:
 747                        output_type = ACPI_DIGITAL_OUTPUT;
 748                        break;
 749                case DRM_MODE_CONNECTOR_LVDS:
 750                        output_type = ACPI_LVDS_OUTPUT;
 751                        break;
 752                }
 753                temp = get_did(opregion, i);
 754                set_did(opregion, i, temp | (1 << 31) | output_type | i);
 755                i++;
 756        }
 757        goto end;
 758}
 759
 760static void intel_setup_cadls(struct drm_device *dev)
 761{
 762        struct drm_i915_private *dev_priv = dev->dev_private;
 763        struct intel_opregion *opregion = &dev_priv->opregion;
 764        int i = 0;
 765        u32 disp_id;
 766
 767        /* Initialize the CADL field by duplicating the DIDL values.
 768         * Technically, this is not always correct as display outputs may exist,
 769         * but not active. This initialization is necessary for some Clevo
 770         * laptops that check this field before processing the brightness and
 771         * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if
 772         * there are less than eight devices. */
 773        do {
 774                disp_id = get_did(opregion, i);
 775                opregion->acpi->cadl[i] = disp_id;
 776        } while (++i < 8 && disp_id != 0);
 777}
 778
 779void intel_opregion_init(struct drm_device *dev)
 780{
 781        struct drm_i915_private *dev_priv = dev->dev_private;
 782        struct intel_opregion *opregion = &dev_priv->opregion;
 783
 784        if (!opregion->header)
 785                return;
 786
 787        if (opregion->acpi) {
 788                intel_didl_outputs(dev);
 789                intel_setup_cadls(dev);
 790
 791                /* Notify BIOS we are ready to handle ACPI video ext notifs.
 792                 * Right now, all the events are handled by the ACPI video module.
 793                 * We don't actually need to do anything with them. */
 794                opregion->acpi->csts = 0;
 795                opregion->acpi->drdy = 1;
 796
 797                system_opregion = opregion;
 798                register_acpi_notifier(&intel_opregion_notifier);
 799        }
 800
 801        if (opregion->asle) {
 802                opregion->asle->tche = ASLE_TCHE_BLC_EN;
 803                opregion->asle->ardy = ASLE_ARDY_READY;
 804        }
 805}
 806
 807void intel_opregion_fini(struct drm_device *dev)
 808{
 809        struct drm_i915_private *dev_priv = dev->dev_private;
 810        struct intel_opregion *opregion = &dev_priv->opregion;
 811
 812        if (!opregion->header)
 813                return;
 814
 815        if (opregion->asle)
 816                opregion->asle->ardy = ASLE_ARDY_NOT_READY;
 817
 818        cancel_work_sync(&dev_priv->opregion.asle_work);
 819
 820        if (opregion->acpi) {
 821                opregion->acpi->drdy = 0;
 822
 823                system_opregion = NULL;
 824                unregister_acpi_notifier(&intel_opregion_notifier);
 825        }
 826
 827        /* just clear all opregion memory pointers now */
 828        memunmap(opregion->header);
 829        opregion->header = NULL;
 830        opregion->acpi = NULL;
 831        opregion->swsci = NULL;
 832        opregion->asle = NULL;
 833        opregion->vbt = NULL;
 834        opregion->lid_state = NULL;
 835}
 836
 837static void swsci_setup(struct drm_device *dev)
 838{
 839        struct drm_i915_private *dev_priv = dev->dev_private;
 840        struct intel_opregion *opregion = &dev_priv->opregion;
 841        bool requested_callbacks = false;
 842        u32 tmp;
 843
 844        /* Sub-function code 0 is okay, let's allow them. */
 845        opregion->swsci_gbda_sub_functions = 1;
 846        opregion->swsci_sbcb_sub_functions = 1;
 847
 848        /* We use GBDA to ask for supported GBDA calls. */
 849        if (swsci(dev, SWSCI_GBDA_SUPPORTED_CALLS, 0, &tmp) == 0) {
 850                /* make the bits match the sub-function codes */
 851                tmp <<= 1;
 852                opregion->swsci_gbda_sub_functions |= tmp;
 853        }
 854
 855        /*
 856         * We also use GBDA to ask for _requested_ SBCB callbacks. The driver
 857         * must not call interfaces that are not specifically requested by the
 858         * bios.
 859         */
 860        if (swsci(dev, SWSCI_GBDA_REQUESTED_CALLBACKS, 0, &tmp) == 0) {
 861                /* here, the bits already match sub-function codes */
 862                opregion->swsci_sbcb_sub_functions |= tmp;
 863                requested_callbacks = true;
 864        }
 865
 866        /*
 867         * But we use SBCB to ask for _supported_ SBCB calls. This does not mean
 868         * the callback is _requested_. But we still can't call interfaces that
 869         * are not requested.
 870         */
 871        if (swsci(dev, SWSCI_SBCB_SUPPORTED_CALLBACKS, 0, &tmp) == 0) {
 872                /* make the bits match the sub-function codes */
 873                u32 low = tmp & 0x7ff;
 874                u32 high = tmp & ~0xfff; /* bit 11 is reserved */
 875                tmp = (high << 4) | (low << 1) | 1;
 876
 877                /* best guess what to do with supported wrt requested */
 878                if (requested_callbacks) {
 879                        u32 req = opregion->swsci_sbcb_sub_functions;
 880                        if ((req & tmp) != req)
 881                                DRM_DEBUG_DRIVER("SWSCI BIOS requested (%08x) SBCB callbacks that are not supported (%08x)\n", req, tmp);
 882                        /* XXX: for now, trust the requested callbacks */
 883                        /* opregion->swsci_sbcb_sub_functions &= tmp; */
 884                } else {
 885                        opregion->swsci_sbcb_sub_functions |= tmp;
 886                }
 887        }
 888
 889        DRM_DEBUG_DRIVER("SWSCI GBDA callbacks %08x, SBCB callbacks %08x\n",
 890                         opregion->swsci_gbda_sub_functions,
 891                         opregion->swsci_sbcb_sub_functions);
 892}
 893#else /* CONFIG_ACPI */
 894static inline void swsci_setup(struct drm_device *dev) {}
 895#endif  /* CONFIG_ACPI */
 896
 897int intel_opregion_setup(struct drm_device *dev)
 898{
 899        struct drm_i915_private *dev_priv = dev->dev_private;
 900        struct intel_opregion *opregion = &dev_priv->opregion;
 901        u32 asls, mboxes;
 902        char buf[sizeof(OPREGION_SIGNATURE)];
 903        int err = 0;
 904        void *base;
 905
 906        BUILD_BUG_ON(sizeof(struct opregion_header) != 0x100);
 907        BUILD_BUG_ON(sizeof(struct opregion_acpi) != 0x100);
 908        BUILD_BUG_ON(sizeof(struct opregion_swsci) != 0x100);
 909        BUILD_BUG_ON(sizeof(struct opregion_asle) != 0x100);
 910
 911        pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
 912        DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls);
 913        if (asls == 0) {
 914                DRM_DEBUG_DRIVER("ACPI OpRegion not supported!\n");
 915                return -ENOTSUPP;
 916        }
 917
 918#ifdef CONFIG_ACPI
 919        INIT_WORK(&opregion->asle_work, asle_work);
 920#endif
 921
 922        base = memremap(asls, OPREGION_SIZE, MEMREMAP_WB);
 923        if (!base)
 924                return -ENOMEM;
 925
 926        memcpy(buf, base, sizeof(buf));
 927
 928        if (memcmp(buf, OPREGION_SIGNATURE, 16)) {
 929                DRM_DEBUG_DRIVER("opregion signature mismatch\n");
 930                err = -EINVAL;
 931                goto err_out;
 932        }
 933        opregion->header = base;
 934        opregion->vbt = base + OPREGION_VBT_OFFSET;
 935
 936        opregion->lid_state = base + ACPI_CLID;
 937
 938        mboxes = opregion->header->mboxes;
 939        if (mboxes & MBOX_ACPI) {
 940                DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
 941                opregion->acpi = base + OPREGION_ACPI_OFFSET;
 942        }
 943
 944        if (mboxes & MBOX_SWSCI) {
 945                DRM_DEBUG_DRIVER("SWSCI supported\n");
 946                opregion->swsci = base + OPREGION_SWSCI_OFFSET;
 947                swsci_setup(dev);
 948        }
 949        if (mboxes & MBOX_ASLE) {
 950                DRM_DEBUG_DRIVER("ASLE supported\n");
 951                opregion->asle = base + OPREGION_ASLE_OFFSET;
 952
 953                opregion->asle->ardy = ASLE_ARDY_NOT_READY;
 954        }
 955
 956        return 0;
 957
 958err_out:
 959        memunmap(base);
 960        return err;
 961}
 962