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 : : }
|