LCOV - code coverage report
Current view: top level - drivers/gpu/drm/i915/display - intel_opregion.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 387 0.0 %
Date: 2022-03-28 15:32:58 Functions: 0 19 0.0 %
Branches: 0 198 0.0 %

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

Generated by: LCOV version 1.14