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